337.打家劫舍 III :递归加记忆

169 阅读3分钟

递归算法

这是leetcode中337. 打家劫舍 III ,难度为中等


题目描述


在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房屋的排列类似于一棵二叉树”。 如果两个直接相连的房子在同一天晚上被打劫,房屋将自动报警。

计算在不触动警报的情况下,小偷一晚能够盗取的最高金额。

示例 1:

输入: [3,2,3,null,3,null,1]

3

/ \

2 3

\ \

3 1

输出: 7

解释: 小偷一晚能够盗取的最高金额 = 3 + 3 + 1 = 7.

示例 2:

输入: [3,4,5,1,3,null,1]

  3

/ \

4 5

/ \ \

1 3 1

输出: 9

解释: 小偷一晚能够盗取的最高金额 = 4 + 5 = 9.

通过次数144,016提交次数237,093

来源:力扣(LeetCode)

链接:leetcode-cn.com/problems/ho…

著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

算法实现


/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {TreeNode} root
 * @return {number}
 */
var rob = function(root) {
    //18点17分 有点不太清楚题意,好像有点明白了,就是不能让偷的房子之间右相互联系的
    //也就是说不能够偷是上下级关系的房子 18点19分
    //18点25分 实在是想不出来,前序遍历,后序遍历,中序遍历,动态规划,都想了一遍都不能够套进入
    //18点42分 看完解析懵懵的,有递归算法和图的动态规划
    //递归算法
    //观察图中可以看出,如果要让一个可收获最大,分为两种情况
    //第一种,抢了当前房子的,抢了以后就只能抢子房子的子房子,不然就会产生联系了
    //第二种,没有抢当前房子的,可以抢房子的左右子房子,然后一次类推
    //比较两种方法,返回最大值
    // var sober = (rootNode) => {
    //     if(rootNode == null) return 0
    //     var the_one = rootNode.val
    //     //如果左边有值的话,就加上左边的子房子
    //     if(rootNode.left){
    //         the_one += sober(rootNode.left.left) + sober(rootNode.left.right) 
    //     }
    //     //如果右边有值的话,就加上右边的子房子
    //     if(rootNode.right){
    //         the_one += sober(rootNode.right.left) + sober(rootNode.right.right)
    //     }
    //     //第二种方法,就是当前的左子树和右子树之和
    //     var the_two = sober(rootNode.left) + sober(rootNode.right)
    //     return Math.max(the_one,the_two)
    // }
    // return sober(root)

    //哎呀,超出时间限制,😅!!!    18点53分
    //又看了一遍的答案,然后发现它加入了记忆的方法
    var map = new Map();
    //温故一下map的使用
    //map保存的是 键 -> 值
    //map.has(key) 表示 是否存在 键 
    //map.size 输出键的多少
    //map.keys() 输出所有的键,这里输出的不是数组,如果要当成数组使用的话,需要进行转化
    //map.values() 输出所有键对应的值
    //map.get(key) 获取键对应的值,比如这道题就是获取rootNode对应的抢劫后的money
    var sober = (rootNode) => {
        if(rootNode == null) return 0
        //如果这个节点存在与map中的话,就返回对应的值
        if(map.has(rootNode)) return map.get(rootNode)
        var the_one = rootNode.val
        //如果左边有值的话,就加上左边的子房子
        if(rootNode.left){
            the_one += sober(rootNode.left.left) + sober(rootNode.left.right) 
        }
        //如果右边有值的话,就加上右边的子房子
        if(rootNode.right){
            the_one += sober(rootNode.right.left) + sober(rootNode.right.right)
        }
        //第二种方法,就是当前的左子树和右子树之和
        var the_two = sober(rootNode.left) + sober(rootNode.right)
        //保存结果
        var res = Math.max(the_one,the_two)
        //设置节点的值
        map.set(rootNode,res)
        return res
    }
    return sober(root)

};

最后


这是我2022年分享的「leetcode」第NO.2篇文章。