返回

刷爆 LeetCode 周赛 337:进阶解题指南,助你制霸位掩码、回溯、同余、分桶和动态规划

后端

LeetCode 周赛 337 第三题:打家劫舍

简介

大家好,我是算法爱好者小彭。上周末举行的 LeetCode 第 337 场周赛,相信大家都有所耳闻。本场周赛虽然难度不高,但题目却极具巧思,考察了位掩码、回溯、同余、分桶和动态规划等多种算法技术。下面,我就带大家深入解析这道题目,领略算法之美。

题目解析:打家劫舍

题目给你一个整数数组 nums,其中 nums[i] 表示第 i 户人家的钱数。你只能抢劫相邻的两家房屋,不能抢劫同一家的房屋两次。请你返回能抢劫的最高金额。

解题思路:动态规划

对于这道题目,我们可以采用动态规划的思想来求解。具体步骤如下:

  1. 定义状态:dp[i] 为抢劫到第 i 户人家的最高金额。
  2. 状态转移方程: dp[i] = max(dp[i-1], dp[i-2] + nums[i])。其中,dp[i-1] 表示不抢劫第 i 户人家,dp[i-2] + nums[i] 表示抢劫第 i 户人家,且不抢劫第 i-1 户人家。
  3. 初始条件: dp[0] = nums[0]dp[1] = max(nums[0], nums[1])
  4. 求解: 根据状态转移方程,依次计算 dp[2]dp[3]、...,直到 dp[n],其中 n 为数组 nums 的长度。

代码实现:

def rob(nums):
  if not nums:
    return 0
  
  dp = [0] * (len(nums) + 1)
  dp[0] = nums[0]
  dp[1] = max(nums[0], nums[1])

  for i in range(2, len(nums)):
    dp[i] = max(dp[i-1], dp[i-2] + nums[i])

  return dp[len(nums) - 1]

复杂度分析:

  • 时间复杂度:O(n),其中 n 为数组 nums 的长度。
  • 空间复杂度:O(n)。

扩展:贪心算法

除了动态规划,我们还可以使用贪心算法来求解这道题目。贪心算法的思路是:在每一步,选择当前能获得最大收益的操作。

具体步骤如下:

  1. 从第 0 户人家开始。
  2. 如果当前人家的钱数大于下一户人家的钱数,则抢劫当前人家。
  3. 否则,跳过当前人家,抢劫下一户人家。
  4. 重复步骤 2 和 3,直到抢劫完所有人家。

代码实现:

def rob_greedy(nums):
  if not nums:
    return 0
  
  money = 0
  prev = 0
  
  for num in nums:
    if num > prev:
      money += num
      prev = num
  
  return money

复杂度分析:

  • 时间复杂度:O(n),其中 n 为数组 nums 的长度。
  • 空间复杂度:O(1)。

总结

通过对 LeetCode 周赛 337 第三题的深入解析,我们掌握了位掩码、回溯、同余、分桶和动态规划等多种算法技术。动态规划是一种求解最优子结构问题的强大技术,而贪心算法是一种简单高效的求解近似最优解的方法。希望这篇文章能帮助大家提升算法思维,在未来的编程竞赛中取得佳绩。

常见问题解答

1. 为什么动态规划比贪心算法更优?

动态规划可以保证找到全局最优解,而贪心算法只能保证局部最优解。在某些情况下,贪心算法可能无法找到全局最优解。

2. 这道题目的扩展可以有哪些?

这道题目可以有多种扩展,例如:

  • 允许抢劫任意相邻或不相邻的房屋。
  • 抢劫的房屋存在冷却时间,抢劫后的一段时间内不能再次抢劫。
  • 抢劫的房屋存在不同的收益和风险。

3. 动态规划中的状态转移方程是如何推导出来的?

状态转移方程是基于题目的约束条件和定义的。对于这道题目,dp[i] 表示抢劫到第 i 户人家的最高金额,而dp[i-1] 表示不抢劫第 i 户人家,dp[i-2] + nums[i] 表示抢劫第 i 户人家,且不抢劫第 i-1 户人家。因此,状态转移方程为 dp[i] = max(dp[i-1], dp[i-2] + nums[i])

4. 贪心算法中,如何判断是否应该抢劫当前人家?

贪心算法中,如果当前人家的钱数大于下一户人家的钱数,则应该抢劫当前人家。这是因为,如果不抢劫当前人家,则下一户人家的钱数会减少,而抢劫当前人家的钱数会增加。

5. 动态规划和贪心算法的优缺点是什么?

  • 动态规划:优点是能保证找到全局最优解,缺点是时间复杂度和空间复杂度较高。
  • 贪心算法:优点是时间复杂度和空间复杂度较低,缺点是不能保证找到全局最优解。