解题思路:动态规划
这是一道典型的 "不相邻元素最大和" 问题,核心是用动态规划递推:
- 定义
dp[i]为前i间房屋能偷到的最大金额。 - 状态转移:
- 若偷第
i间,则不能偷第i-1间:dp[i] = dp[i-2] + nums[i] - 若不偷第
i间,则最大金额为dp[i-1] - 因此:
dp[i] = max(dp[i-1], dp[i-2] + nums[i])
- 若偷第
- 空间优化:只需维护前两个状态,用两个变量滚动更新,空间复杂度从 O (n) 降到 O (1)。
基础动态规划版(未做空间优化)
这个版本会完整维护一个 dp 数组,存储前 i 间房屋的最大金额,逻辑更直观,适合理解动态规划的核心思想:
class Solution {
public int rob(int[] nums) {
// 边界条件处理
if (nums == null || nums.length == 0) {
return 0;
}
if (nums.length == 1) {
return nums[0];
}
// 1. 定义dp数组:dp[i]表示前i间房屋能偷到的最大金额
int[] dp = new int[nums.length];
// 2. 初始化dp数组
dp[0] = nums[0]; // 只有1间房,偷它
dp[1] = Math.max(nums[0], nums[1]); // 有2间房,偷金额大的那个
// 3. 状态转移:遍历从第3间房开始(索引2)
for (int i = 2; i < nums.length; i++) {
// 两种选择:偷第i间(则不能偷i-1,取dp[i-2]+nums[i]);不偷第i间(取dp[i-1])
dp[i] = Math.max(dp[i-1], dp[i-2] + nums[i]);
}
// 4. 最终结果是最后一间房对应的dp值
return dp[nums.length - 1];
}
}

代码实现(空间优化版)
class Solution {
public int rob(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
if (nums.length == 1) {
return nums[0];
}
int prevPrev = nums[0]; // dp[i-2]
int prev = Math.max(nums[0], nums[1]); // dp[i-1]
for (int i = 2; i < nums.length; i++) {
int curr = Math.max(prev, prevPrev + nums[i]);
prevPrev = prev;
prev = curr;
}
return prev;
}
}

复杂度分析
- 时间复杂度:O (n),一次遍历数组。
- 空间复杂度:O (1),仅用两个变量滚动更新,满足常量空间要求。
示例验证
-
示例 1 :
nums = [1,2,3,1]- i=0: prevPrev=1, prev=max(1,2)=2
- i=2: curr = max(2, 1+3)=4 → prevPrev=2, prev=4
- i=3: curr = max(4, 2+1)=4 → prev=4
- 输出:4
-
示例 2 :
nums = [2,7,9,3,1]- i=0: prevPrev=2, prev=7
- i=2: curr = max(7, 2+9)=11 → prevPrev=7, prev=11
- i=3: curr = max(11, 7+3)=11 → prevPrev=11, prev=11
- i=4: curr = max(11, 11+1)=12 → prev=12
- 输出:12
扩展
一、核心算法思想回顾
先明确算法的核心适配场景:
- 存在线性排列的可选项 (如房屋、时间段、资源节点);
- 有 "相邻项互斥" 的约束(选了 A 就不能选 A 的直接邻居);
- 目标是最大化收益 / 最小化成本 。
这三个特征是判断能否用该算法的关键,也是它能落地到生产的核心原因。
二、实际生产场景落地(附代码示例)
场景 1:广告位投放优化(电商 / 信息流平台)
业务背景
APP 首页有一排广告位(位置 0→1→2→...→n-1),每个广告位投放后能获得的收益为
profit[i],但平台规则要求相邻广告位不能投放同一品牌(避免用户视觉疲劳),需要计算 "投放哪些广告位能获得最大总收益"。
算法适配性
- 广告位 = 房屋,投放收益 = 房屋金额;
- 相邻广告位互斥 = 相邻房屋不能偷;
- 目标:最大化总收益 = 最大化偷到的金额。
生产级代码实现(Java)
/**
* 广告位投放最大收益计算(基于打家劫舍DP算法)
*/
public class AdSlotOptimizer {
// 核心算法:计算最大投放收益
public static int calculateMaxAdProfit(int[] slotProfits) {
if (slotProfits == null || slotProfits.length == 0) return 0;
if (slotProfits.length == 1) return slotProfits[0];
// 基础DP版(便于生产环境调试,可记录中间状态)
int[] dp = new int[slotProfits.length];
dp[0] = slotProfits[0];
dp[1] = Math.max(slotProfits[0], slotProfits[1]);
for (int i = 2; i < slotProfits.length; i++) {
dp[i] = Math.max(dp[i-1], dp[i-2] + slotProfits[i]);
// 生产环境可打印中间状态,用于监控/调试
System.out.printf("广告位%d:不投放收益=%d,投放收益=%d,最优=%d%n",
i, dp[i-1], dp[i-2]+slotProfits[i], dp[i]);
}
return dp[slotProfits.length - 1];
}
public static void main(String[] args) {
// 模拟广告位收益:位置0=500元,位置1=300元,位置2=800元,位置3=400元
int[] slotProfits = {500, 300, 800, 400};
int maxProfit = calculateMaxAdProfit(slotProfits);
System.out.println("广告投放最大收益:" + maxProfit); // 结果:500+800=1300元
}
}
生产价值
- 电商大促(618 / 双 11)时,广告位收益实时变化,该算法能快速计算最优投放方案;
- 支持动态调整:若某广告位临时不可用(收益设为 0),算法可实时重新计算,适配业务变化。
场景 2:服务器资源调度(云服务平台)
业务背景
云服务器集群按机架线性排列(机架 0→1→2→...→n-1),每个机架部署任务的收益为
reward[i],但相邻机架不能同时部署高负载任务(避免电力过载),需要计算 "部署哪些机架能获得最大总收益"。
算法适配性
- 机架 = 房屋,部署收益 = 房屋金额;
- 相邻机架互斥 = 相邻房屋不能偷;
- 目标:最大化集群收益 = 最大化偷到的金额。
核心代码(空间优化版,适配高并发)
/**
* 服务器机架资源调度(空间优化版,适合大规模集群)
*/
public class ServerResourceScheduler {
public static int maxClusterReward(int[] rackRewards) {
if (rackRewards == null || rackRewards.length == 0) return 0;
if (rackRewards.length == 1) return rackRewards[0];
// 空间优化版:适合机架数上千的大规模集群,节省内存
int prevPrev = rackRewards[0];
int prev = Math.max(rackRewards[0], rackRewards[1]);
for (int i = 2; i < rackRewards.length; i++) {
int curr = Math.max(prev, prevPrev + rackRewards[i]);
prevPrev = prev;
prev = curr;
}
return prev;
}
public static void main(String[] args) {
// 模拟1000个机架的收益(随机生成,仅示例)
int[] rackRewards = new int[1000];
for (int i = 0; i < 1000; i++) {
rackRewards[i] = (int) (Math.random() * 1000);
}
long startTime = System.currentTimeMillis();
int maxReward = maxClusterReward(rackRewards);
long endTime = System.currentTimeMillis();
System.out.println("集群最大收益:" + maxReward);
System.out.println("计算耗时:" + (endTime - startTime) + "ms"); // 毫秒级,满足实时调度
}
}
生产价值
- 云平台机架数可达上千 / 上万,空间优化版仅用 2 个变量,内存占用可忽略;
- 时间复杂度 O (n),毫秒级完成计算,满足资源调度的实时性要求(调度决策需在秒级内完成)。
场景 3:电网负荷分配(能源行业)
业务背景
电网的输电节点按线路线性排列,每个节点的供电收益为
profit[i],但相邻节点不能同时满负荷供电(避免线路过载),需要计算 "哪些节点供电能获得最大总收益"。
算法适配性
- 输电节点 = 房屋,供电收益 = 房屋金额;
- 相邻节点互斥 = 相邻房屋不能偷;
- 目标:最大化供电收益 = 最大化偷到的金额。
扩展:最小成本版本(反向应用)
生产中也常遇到 "最小成本" 场景,比如 "相邻节点不能同时断电,求最小断电损失",只需把 max 换成 min:
/**
* 电网节点断电最小损失计算(反向应用打家劫舍算法)
*/
public class PowerGridOptimizer {
public static int minPowerLoss(int[] loss) {
if (loss == null || loss.length == 0) return 0;
if (loss.length == 1) return loss[0];
int[] dp = new int[loss.length];
dp[0] = loss[0];
dp[1] = Math.min(loss[0], loss[1]); // 换成min求最小损失
for (int i = 2; i < loss.length; i++) {
dp[i] = Math.min(dp[i-1], dp[i-2] + loss[i]);
}
return dp[loss.length - 1];
}
}
三、算法扩展:生产环境的进阶适配
在实际生产中,基础算法会根据业务需求扩展,核心思路不变:
- 环形约束(打家劫舍 II):比如广告位围成一圈(首尾也互斥),只需拆分为 "不选第一个" 和 "不选最后一个" 两个子问题,分别计算取最大值;
- 多维度约束 :比如广告位不仅相邻互斥,还受 "每日投放次数限制",可扩展为二维 DP 数组
dp[i][k](前 i 个广告位,投放 k 次的最大收益); - 实时更新:生产中收益 / 成本会动态变化,可结合滑动窗口,只重新计算变化的区间,提升效率。
总结
- 核心应用场景:所有 "线性排列 + 相邻互斥 + 最优选择" 的场景,如广告投放、资源调度、能源分配、任务规划等;
- 生产选型建议 :
- 小规模场景 / 需要调试:用基础 DP 版(便于记录中间状态);
- 大规模场景 / 高并发:用空间优化版(节省内存,提升速度);
- 扩展价值:不仅能求 "最大值",也能反向求 "最小值",适配收益 / 成本两类核心业务目标。

