返回
动脑筋斗智斗勇,算法解题:打家劫舍
前端
2023-10-07 01:14:44
在这场刺激的智力竞赛中,你必须成为一位技术高超的小偷,熟练运用动态规划算法,在不触发警报的情况下从一排房屋中窃取最大金额。准备好磨练你的算法技能了吗?让我们开始吧!
动态规划:巧妙解题之道
动态规划是一种强大的算法技术,特别适合解决涉及重叠子问题的优化问题。在打家劫舍问题中,相邻房屋的约束条件引入了重叠的子问题,而动态规划为我们提供了以高效的方式解决问题的理想方法。
算法步骤:
- 定义状态: 用
dp[i]
表示考虑前i
间房屋时能窃取到的最大金额。 - 状态转移方程:
dp[i] = max(dp[i - 1], dp[i - 2] + loot[i])
dp[i - 1]
表示不窃取第i
间房屋能获得的最大金额。dp[i - 2] + loot[i]
表示窃取第i
间房屋且不触发警报能获得的最大金额,因为相邻房屋不能同时被窃取。
- 边界条件:
dp[0] = 0
,dp[1] = loot[1]
代码实现:
def rob(nums):
if not nums:
return 0
dp = [0] * len(nums)
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[-1]
实例演示:
让我们用一个示例来说明算法的运作方式:
房屋金额:[2, 7, 9, 3, 1]
子问题分解:
- 考虑前 1 间房屋:
dp[1] = 2
- 考虑前 2 间房屋:
dp[2] = max(2, 7) = 7
- 考虑前 3 间房屋:
dp[3] = max(7, 2 + 9) = 11
- 考虑前 4 间房屋:
dp[4] = max(11, 7 + 3) = 14
- 考虑前 5 间房屋:
dp[5] = max(14, 11 + 1) = 15
因此,从这排房屋中能窃取到的最大金额为 15
。
优化技巧:
为了进一步优化算法,我们可以使用滚动数组来节省空间。滚动数组利用了状态转移方程中只依赖于前两个状态的特性。
def rob_optimized(nums):
if not nums:
return 0
prev1 = 0
prev2 = 0
for num in nums:
temp = max(prev2 + num, prev1)
prev2 = prev1
prev1 = temp
return prev1
使用滚动数组后,算法的空间复杂度从 O(n)
降低到 O(1)
,其中 n
是房屋的数量。
结语:
打家劫舍问题完美诠释了动态规划算法的强大功能。通过将问题分解成较小的子问题并巧妙地使用状态转移方程,我们可以高效地找到最佳解决方案。无论你是一个经验丰富的程序员还是算法新手,我都鼓励你动手尝试一下,磨练你的算法技能。祝你在解题中收获乐趣和洞见!