• 力扣198题、213题、337题(打家劫舍)


    198、打家劫舍

    基本思想:

    动态规划

    具体实现:

    1、确认状态

    dp[i]=前 i 个房子在满足条件下的能偷窃到的最高金额。

    2、状态转移

    由于不可以在相邻的房屋闯入,所以在当前位置 i 房屋可盗窃的最大值,

    要么就是 i-1 房屋可盗窃的最大值,

    要么就是 i-2 房屋可盗窃的最大值加上当前房屋的值,二者之间取最大值

    dp[i] = max(dp[i-1],nums[i-1]+dp[i-2])

    3、计算顺序

    从前到后遍历

    4、初始状态

    从递推公式dp[i] = max(dp[i - 2] + nums[i], dp[i - 1]);可以看出,递推公式的基础就是dp[0] 和 dp[1]

    从dp[i]的定义上来讲,dp[0] 一定是 nums[0],dp[1]就是nums[0]和nums[1]的最大值即:dp[1] = max(nums[0], nums[1]);

    5、举例推导dp数组

    代码:

    class Solution {
        public int rob(int[] nums) {
            if (nums == null || nums.length == 0) return 0;
            if (nums.length == 1) return nums[0];
             int[] dp = new int[nums.length];
             dp[0] = nums[0];
             dp[1] = Math.max(dp[0], nums[1]);
             for (int i = 2; i < nums.length; i++){
                 dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
             }
    
             return dp[nums.length - 1];
        }
    }

    213、打家劫舍II

    基本思想:

    与上一题的区别是成环了

    具体实现:

    1、考虑取第一间房子的钱,不取最后一间房子的钱(是考虑,不是非要取)

    2、考虑取最后一间房子的钱,不取第一间房子的钱

    3、考虑第一间和最后一件都不取

    情况1,2包括了情况3

    代码:

    class Solution:
        def rob(self, nums: List[int]) -> int:
            def my_rob(nums):
                cur, pre = 0, 0
                for num in nums:
                    cur, pre = max(pre + num, cur), cur
                return cur
            if len(nums) != 1:
                return max(my_rob(nums[:-1]),my_rob(nums[1:]))
            else:
                return nums[0]
    class Solution {
        public int rob(int[] nums) {
            if (nums.length == 0) return 0;
            if (nums.length == 1) return nums[0];
            int result1 = robRange(nums, 0, nums.length - 2);
            int result2 = robRange(nums, 1, nums.length - 1);
            return Math.max(result1, result2);
        }
    
        public int robRange(int[] nums, int start, int end) {
            if (end == start) return nums[start];
             int[] dp = new int[nums.length];
             dp[start] = nums[start];
             dp[start + 1] = Math.max(nums[start], nums[start + 1]);
             for (int i = start + 2; i <= end; i++){
                 dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
             }
    
             return dp[end];
        }
    }

    337、打家劫舍III

    基本思想:

    动态规划

    后序遍历,因为通过递归函数的返回值来做下一步计算。

    具体实现:

    1、确认状态

    求一个节点 偷与不偷的两个状态所得到的金钱,那么返回值就是一个长度为2的数组。

    dp数组(dp table)以及下标的含义:下标为0记录不偷该节点所得到的的最大金钱,下标为1记录偷该节点所得到的的最大金钱。

    长度为2的数组怎么标记树中每个节点的状态呢?

    在递归的过程中,系统栈会保存每一层递归的参数。

    2、确定终止条件

    遍历的过程中,如果遇到空节点的话,很明显,无论偷还是不偷都是0,所以就返回

    3、遍历顺序

    首先明确的是使用后序遍历。 因为通过递归函数的返回值来做下一步计算。

    通过递归左节点,得到左节点偷与不偷的金钱。

    通过递归右节点,得到右节点偷与不偷的金钱。

    4、单层递归逻辑

    任何一个节点能偷到的最大钱的状态可以定义为

    当前节点选择不偷:当前节点能偷到的最大钱数 = 左孩子能偷到的钱 + 右孩子能偷到的钱
    当前节点选择偷:当前节点能偷到的最大钱数 = 不偷左孩子处能得到的钱 + 不偷右孩子处能得到的钱 + 当前节点的钱数

    root[0] = Math.max(rob(root.left)[0], rob(root.left)[1]) + Math.max(rob(root.right)[0], rob(root.right)[1])
    root[1] = rob(root.left)[0] + rob(root.right)[0] + root.val;

    代码:

    class Solution:
        def rob(self, root: TreeNode) -> int:
            def robInternal(root):
                if root == None:
                    return 0,0
                
                left = robInternal(root.left)
                right = robInternal(root.right)
                result_0 = max(left[0],left[1])+max(right[0],right[1])
                result_1 = left[0] + right[0] + root.val
                
                return result_0,result_1
            
            return max(robInternal(root))   
    class Solution:
        def rob(self, root: TreeNode) -> int:
            def robInternal(root):
                if root == None:
                    return 0,0
                result = [0,0]
                left = robInternal(root.left)
                right = robInternal(root.right)
                result[0] = max(left[0],left[1])+max(right[0],right[1])
                result[1] = left[0] + right[0] + root.val
                
                return result
  • 相关阅读:
    wcf中的Message类
    wcf消息契约
    iis部署wcf服务
    WCF数据契约
    wcf配置
    wcf中的使用全双工通信
    A股主要指数的市盈率(PE)估值高度
    股票的历史市盈率查询PE
    错误 Unable to find vcvarsall.bat 的终极无敌最完美的解决办法
    A股最新的自由现金流和折现估值查询
  • 原文地址:https://www.cnblogs.com/zhaojiayu/p/14572775.html
Copyright © 2020-2023  润新知