算法练习day41

86 阅读3分钟

一、打家劫舍

当前房屋偷与不偷,取决于前一个房屋和前两个房屋是否被偷

五部曲

  1. dp[i],表示i以内的房屋,最多可以偷窃的金额
  2. 确定递推公式,dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1])
  3. 确定初始值,dp[0] = nums[0];dp[1] = Math.max(nums[0], nums[1])
  4. 确定遍历顺序,从前到后
  5. 举例推导
/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function(nums) {
    let dp = new Array(nums.length).fill(0)
    dp[0] = nums[0]
    dp[1] = Math.max(nums[0], nums[1])
    for(let i = 2; i < nums.length;i++) {
        dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1])
    }
    return dp[nums.length - 1]
};

二、打家劫舍2

和上题的区别在于,是环形

有两种场景

  1. 不考虑首元素下的最大总金额
  2. 不考虑尾元素下的最大总金额

结果,取这两种情况的最大值即可

/**
 * @param {number[]} nums
 * @return {number}
 */
var rob = function(nums) {
    if(nums.length === 0) {
        return 0
    }
    if(nums.length === 1) {
        return nums[0]
    }
    let result1 = robRange(nums.slice(0, nums.length - 1))
    let result2 = robRange(nums.slice(1, nums.length))
    return Math.max(result1, result2)
};
var robRange = function(nums) {
    let dp = new Array(nums.length).fill(0)
    dp[0] = nums[0]
    dp[1] = Math.max(nums[0], nums[1])
    for(let i = 2; i < nums.length;i++) {
        dp[i] = Math.max(dp[i-2] + nums[i], dp[i-1])
    }
    return dp[nums.length - 1]
};

三、打家劫舍3

暴力解法,后序遍历

超时,计算过程重复

/**
 * 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) {
    function dfs(node) {
        if (!node) {
            return 0
        }
        if (!node.left && !node.right) {
            return node.val
        }
        let val1 = node.val
        if (node.left) {
            val1 += dfs(node.left.left) + dfs(node.left.right)
        }
        if (node.right) {
            val1 += dfs(node.right.left) + dfs(node.right.right)
        }
        let val2 = dfs(node.left) + dfs(node.right)
        let res = 
        return Math.max(val1, val2)
    }
    return dfs(root)
};

时间复杂度为O(n^2),空间复杂度为O(logn)

记忆搜索

/**
 * 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) {
    let map = new Map
    function dfs(node) {
        if (!node) {
            return 0
        }
        if (!node.left && !node.right) {
            return node.val
        }
        if(map.has(node)) {
            return map.get(node)
        }
        let val1 = node.val
        if (node.left) {
            val1 += dfs(node.left.left) + dfs(node.left.right)
        }
        if (node.right) {
            val1 += dfs(node.right.left) + dfs(node.right.right)
        }
        let val2 = dfs(node.left) + dfs(node.right)
        let res = Math.max(val1, val2)
        map.set(node, res)
        return res
    }
    return dfs(root)
};

时间复杂度为On,空间复杂度为Ologn

动态规划

深度递归搜索对每个节点偷与不偷没有做记录,动态规划需要使用动态转移容器来记录状态的变化,可以使用长度为2的数组,记录当前节点偷或者不偷,得到的最大金钱

树形dp,基于递归三部曲+动态规划五部曲

  1. 确定递归函数的参数和返回值, dp数组为长度为2的数组,表示当前节点偷或者不偷,索引0,表示不偷,索引1表示偷,得到的最大金钱,递归的过程中,系统栈会保存每一层递归的参数
function robTree(node: number): [number, number] {
    return []
}
  1. 确定终止条件,空节点,偷或不偷,都是0
if(!node) {
    return [0, 0]
}
  1. 确定遍历顺序,后序遍历,需要通过递归遍历的返回值做下一步计算
  2. 确定单层递归的逻辑
    1. 如果偷当前节点,则左右孩子就不能偷,val + left[0] + right[0]
    2. 如果不偷当前节点,则左右孩子可以偷,得到两种情况的最大值,val2 = Math.max(left[0], left[1]) + Math.max(right[0], right[1])
  3. 举例推导
var rob = function (root) {
    function dfs(node) {
        if(!node) {
            return [0, 0]
        }
        let left = dfs(node.left)
        let right = dfs(node.right)
        // 不偷当前节点,取偷左孩子,或者不偷左孩子和偷右孩子或不偷右孩子的最大值之和
        let val1 = Math.max(...left) + Math.max(...right)
        // 偷当前节点,取左右孩子节点不偷的结果
        let val2 = node.val + left[0] + right[0]
        return [val1, val2]
    }
    return Math.max(...dfs(root))
};