动态规划day06
139. 单词拆分
class Solution {
public boolean wordBreak(String s, List<String> wordDict) {
int len = s.length();
boolean[] dp = new boolean[len + 1];
Set<String> hash = new HashSet<>(wordDict);
dp[0] = true;
for (int i = 1; i <= len; i++) {
for (int j = 0; j < i; j++) {
//保证是连续的存在于字典中
if (hash.contains(s.substring(j, i)) && dp[j]) {
dp[i] = true;
break;
}
}
}
return dp[len];
}
}
198. 打家劫舍
class Solution {
public int rob(int[] nums) {
if (nums.length == 1) return nums[0];
int[] dp = new int[nums.length];
dp[0] = nums[0];
dp[1] = nums[1] > nums[0] ? nums[1] : nums[0];
for (int i = 2; i < nums.length; i++) {
//递推式 i-1就是前面元素集合的最优解
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
}
return dp[nums.length - 1];
}
}
213. 打家劫舍 II
class Solution {
public int rob(int[] nums) {
int len = nums.length;
//三种情况 不偷首家 不偷尾家 首尾都不偷(前面两种情况包含了)
if (len == 1) return nums[0];
return Math.max(dpRob(nums, 0, len - 2), dpRob(nums, 1, len - 1));
}
//dp逻辑
private int dpRob(int[] nums, int s, int e) {
if (s == e) return nums[s];
int len = e - s + 1;
int[] dp = new int[len];
dp[0] = nums[s];
dp[1] = Math.max(nums[s], nums[s + 1]);
for (int i = 2; i < len; i++) {
dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i + s]);
}
return dp[len - 1];
}
}
337. 打家劫舍 III
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public int rob(TreeNode root) {
//使用长度为2的数组存偷该结点(下标0)和不偷该结点(下标1)对应金额
int[] res = postOrder(root);
return Math.max(res[0], res[1]);
}
private int[] postOrder(TreeNode cur) {
if (cur == null) return new int[]{0, 0};
int[] left = postOrder(cur.left);
int[] right = postOrder(cur.right);
//偷该结点 下标0 递推式cur.val + left[1] + right[1];
int val0 = cur.val + left[1] + right[1];
//不偷该节点 下标1 递推式max(left[0], left[1]) + max(right[0], right[1]);
int val1 = Math.max(left[0], left[1]) + Math.max(right[0], right[1]);
return new int[]{val0, val1};
}
}
121. 买卖股票的最佳时机
// class Solution {
// public int maxProfit(int[] prices) {
// int n = prices.length;
// int[][] dp = new int[n][2];
// //一开始只有0元 dp[0][0]代表在第一天买入 dp[0][1]第一天不买入(默认0)
// dp[0][0] = -prices[0];
// for (int i = 1; i < n; i++) {
// //i + 1天买入,继续持有和当天买入孰大孰小
// dp[i][0] = Math.max(dp[i - 1][0], -prices[i]);
// //卖出,继续不买入和当天卖出
// dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
// }
// //最后肯定是卖出了的
// return dp[n - 1][1];
// }
// }
//动规优化
// class Solution {
// public int maxProfit(int[] prices) {
// //当天状态只与昨天状态有关,可以只用一个长度为2的一维数组记录
// int[] dp = new int[2];
// dp[0] = -prices[0];
// for (int i = 1; i < prices.length; i++) {
// //先算卖出的,因为要用到昨天买入的状态
// dp[1] = Math.max(dp[0] + prices[i], dp[1]);
// dp[0] = Math.max(dp[0], -prices[i]);
// }
// return dp[1];
// }
// }
//贪心
class Solution {
public int maxProfit(int[] prices) {
//左边找最低价格,右边最高价格
int minP = Integer.MAX_VALUE, res = 0;
for (int i = 0; i < prices.length; i++) {
minP = Math.min(minP, prices[i]);
res = Math.max(res, prices[i] - minP);
}
return res;
}
}