动态规划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;
    }
}

参考:programmercarl.com

 

posted @ 2022-06-23 21:07  一梦两三年13  阅读(14)  评论(0编辑  收藏  举报