620 字
3 分钟
打家劫舍

题目描述
你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。
给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。
解题思路
- 动态规划:
- 定义
dp[i]
表示前i
个房屋能偷窃的最大金额 - 状态转移:
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
- 定义
- 滚动优化:
- 仅需维护前两个状态(prev 和 curr)
- 空间复杂度从 O(n) 降至 O(1)
- 边界处理:
- 空数组返回 0
- 单房屋返回其金额
- 决策逻辑:
- 不偷当前房屋:继承前一个状态
- 偷当前房屋:前前状态 + 当前金额
关键洞察
- 最优子结构:
- 当前最优解由子问题最优解构成
- 无后效性:后续决策不影响已决定房屋
- 状态依赖:
- 仅依赖前两个房屋的状态
- 无需记录完整历史决策
- 滚动技巧:
- 用两个变量交替更新状态
- 避免存储整个 DP 数组
- 决策分离:
- 偷与不偷的决策相互独立
- 取最大值保证全局最优
复杂度分析
指标 | 说明 |
---|---|
时间复杂度 | O(n):单次遍历数组 |
空间复杂度 | O(1):仅需两个变量存储状态 |
最优情况 | O(n):必须遍历所有房屋 |
代码实现
/** * @param {number[]} nums * @return {number} */var rob = function(nums) { if(nums.length <= 2) return Math.max(...nums); let p1 = nums[0],p2 = Math.max(nums[0],nums[1]); let result = null; for(let i=2;i<nums.length;i++){ result = Math.max(p1+nums[i],p2); p1 = p2; p2 = result; } return result;};
实际应用场景
- 资源调度:互斥任务的最大收益调度`
- 投资组合:互斥投资项目的最大收益选择`
- 路径规划:互斥路径点的最大收益采集`
- 游戏策略:回合制游戏的互斥行动选择`