从佰草园(打家劫舍)到三味书屋(打家劫舍II)

1,130 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第7天,点击查看活动详情

198. 打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

示例 1:

输入: [1,2,3,1]
输出: 4
解释: 偷窃 1 号房屋 (金额 = 1) ,然后偷窃 3 号房屋 (金额 = 3)。
     偷窃到的最高金额 = 1 + 3 = 4

示例 2:

输入: [2,7,9,3,1]
输出: 12
解释: 偷窃 1 号房屋 (金额 = 2), 偷窃 3 号房屋 (金额 = 9),接着偷窃 5 号房屋 (金额 = 1)。
     偷窃到的最高金额 = 2 + 9 + 1 = 12

解题思路

其实这个题目就是:替换。当前的偷窃的房子的值,和不能偷窃的值比较一下那个大?

  1. 我们需要确定一个初始目标和选中初始目标之后的值
let p1 = num[0]
let res = Math.max(num[0], num[1]) // 这里不难理解就是二选一,选出大的哪一个
  1. 然后我们需要开始从第二个值开始遍历:
for(let i = 0; i< nums.length; i++) {
    ...
}
  1. 遍历过程中我们需要做什么? 这里我们来个简单的流程图来演示一下:
    沿街的房屋:【2,1,3,4,5,9】: 初始开始时候:
  • p1 = 2(就是我们当前进入房间之前的值)
  • res = 2(最终结果值) 然后我们进入第三间房间:
  • 此时我们可以选择 抢这个房间或者不抢这个房间
  • 如果不抢这个房间的值 = ?
  • 如果抢这个房间的值 = ? 这都需要我们进行记录
const temp = res // 记录一下我们进入房间的时候我们已经获取到的值
res = Math.max(p1 + num[i], res) // 这时候我们就需要进行比较,进去这个房间之后是抢还是不抢
p1 = temp // 这时候我们就出房间了 那之前存储的 temp 就是我们进入下一个房间之前的值

最终代码

 var rob = function(nums) {
  if(nums.length < 2){
      return nums[0]
  }
  let p1 = nums[0]
  let res = Math.max(nums[0], nums[1])
  for(let i = 2; i<nums.length; i++) {
    const temp = res
    res = Math.max(p1+ nums[i], res)
    p1 =temp
  }
  return res
};

另一个版本

也是利用递推

var rob = function(nums) {
  if(!nums.length){
      return 0
  }
  const dp = new Array(nums.length + 1);
  dp[0] = 0;
  dp[1] = nums[0];
  for(let i = 2; i <= nums.length; i++) {
      dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i-1]);
  }
  console.log(dp)
  return dp[nums.length];
};

解析:

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

这里是为了记录我们在当前节点的时候已经获取到的值。其实就是一个累加的过程。

我们使用示例1进行测试,最终dp的输出是: [ 0, 1, 2, 4, 4 ]

进阶 打家劫舍 II

题目详情链接:leetcode.cn/problems/ho…

...这个地方所有的房屋都 围成一圈 ,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警 ...

有了上一题的经验,其实这个题目也很简单,不让我们同时偷第一个和最后一个房屋嘛,那我们就可以:

image.png

image.png

如上图,将数组拆分成前后两个,然后取得结果后进行比对

 var rob = function(nums) {
  if(nums.length <= 1){
    return nums[0]
  }
  let res1 = robCompare(nums.slice(0, nums.length -1))
  let res2 = robCompare(nums.slice(1, nums.length))
  return Math.max(res1, res2)
};
const robCompare = (nums) => {
  if(nums.length <= 1){
    return nums[0]
  }
  let first = nums[0]
  let second = Math.max(first, nums[1])
  for(let i = 2; i< nums.length; i++){
    const temp = second
    second = Math.max(first + nums[i], second)
    first = temp
  }
  return second
}