LeetCode 198: House Robber

LeetCode 198: House Robber

    • [1. 📌 Problem Links](#1. 📌 Problem Links)
    • [2. 🧠 Solution Overview](#2. 🧠 Solution Overview)
    • [3. 🟢 Solution 1: Dynamic Programming (Bottom-Up)](#3. 🟢 Solution 1: Dynamic Programming (Bottom-Up))
      • [3.1. Algorithm Idea](#3.1. Algorithm Idea)
      • [3.2. Key Points](#3.2. Key Points)
      • [3.3. Java Implementation](#3.3. Java Implementation)
      • [3.4. Complexity Analysis](#3.4. Complexity Analysis)
    • [4. 🟡 Solution 2: Space-Optimized Dynamic Programming](#4. 🟡 Solution 2: Space-Optimized Dynamic Programming)
      • [4.1. Algorithm Idea](#4.1. Algorithm Idea)
      • [4.2. Key Points](#4.2. Key Points)
      • [4.3. Java Implementation](#4.3. Java Implementation)
      • [4.4. Complexity Analysis](#4.4. Complexity Analysis)
    • [5. 🔵 Solution 3: Recursive Approach with Memoization](#5. 🔵 Solution 3: Recursive Approach with Memoization)
      • [5.1. Algorithm Idea](#5.1. Algorithm Idea)
      • [5.2. Key Points](#5.2. Key Points)
      • [5.3. Java Implementation](#5.3. Java Implementation)
      • [5.4. Complexity Analysis](#5.4. Complexity Analysis)
    • [6. 📊 Solution Comparison](#6. 📊 Solution Comparison)
    • [7. 💡 Summary](#7. 💡 Summary)

LeetCode 198: House Robber

2. 🧠 Solution Overview

This problem requires finding the maximum amount of money you can rob from houses arranged in a straight line without alerting the police. The constraint is that you cannot rob two adjacent houses. Below are the main approaches:

Method Key Idea Time Complexity Space Complexity
Dynamic Programming DP array storing max profit at each house O(n) O(n)
Space-Optimized DP Two variables tracking previous states O(n) O(1)
Recursive with Memoization Top-down approach with caching O(n) O(n)

3. 🟢 Solution 1: Dynamic Programming (Bottom-Up)

3.1. Algorithm Idea

We use a DP array where dp[i] represents the maximum amount that can be robbed from the first i+1 houses. The key insight is that at each house i, we have two choices: either rob this house and add its value to the maximum amount from houses up to i-2, or skip this house and take the maximum amount from houses up to i-1.

3.2. Key Points

  • State Definition : dp[i] = maximum amount robbable from first i+1 houses
  • State Transition :
    • If we rob house i: dp[i] = dp[i-2] + nums[i]
    • If we skip house i: dp[i] = dp[i-1]
    • Final: dp[i] = max(dp[i-1], dp[i-2] + nums[i])
  • Initialization :
    • dp[0] = nums[0] (only one house)
    • dp[1] = max(nums[0], nums[1]) (two houses)
  • Processing Order: Left to right, ensuring subproblems are solved first

3.3. Java Implementation

java 复制代码
class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return nums[0];
        }
        
        int n = nums.length;
        int[] dp = new int[n];
        dp[0] = nums[0];
        dp[1] = Math.max(nums[0], nums[1]);
        
        for (int i = 2; i < n; i++) {
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i]);
        }
        
        return dp[n - 1];
    }
}

3.4. Complexity Analysis

  • Time Complexity : O(n) - Single pass through all houses
  • Space Complexity : O(n) - DP array of size n

4. 🟡 Solution 2: Space-Optimized Dynamic Programming

4.1. Algorithm Idea

We can optimize space by noticing that only the previous two states (i-1 and i-2) are needed to compute the current state i. Instead of storing the entire DP array, we maintain only two variables that represent these states and update them iteratively.

4.2. Key Points

  • Variable Tracking :
    • prev1 tracks maximum up to previous house (i-1)
    • prev2 tracks maximum up to two houses before (i-2)
  • State Update: At each iteration, calculate current maximum and shift variables
  • Edge Cases: Handle empty array, single house, and two houses separately

4.3. Java Implementation

java 复制代码
class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        if (nums.length == 1) {
            return nums[0];
        }
        
        int prev2 = 0; // Represents dp[i-2]
        int prev1 = 0; // Represents dp[i-1]
        
        for (int num : nums) {
            int current = Math.max(prev1, prev2 + num);
            prev2 = prev1;
            prev1 = current;
        }
        
        return prev1;
    }
}

4.4. Complexity Analysis

  • Time Complexity : O(n) - Same as standard DP
  • Space Complexity : O(1) - Only two variables used

5. 🔵 Solution 3: Recursive Approach with Memoization

5.1. Algorithm Idea

This approach solves the problem recursively from the top (end of the street) down to the beginning, caching results to avoid redundant calculations. For each house, we explore both possibilities (rob or skip) and return the maximum.

5.2. Key Points

  • Recursive Relation : rob(i) = max(rob(i-1), rob(i-2) + nums[i])
  • Base Cases :
    • i < 0: return 0 (no houses)
    • i == 0: return nums[0] (only one house)
  • Memoization: Store computed results to avoid exponential time complexity

5.3. Java Implementation

java 复制代码
class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        Integer[] memo = new Integer[nums.length];
        return robHelper(nums, nums.length - 1, memo);
    }
    
    private int robHelper(int[] nums, int i, Integer[] memo) {
        if (i < 0) {
            return 0;
        }
        if (memo[i] != null) {
            return memo[i];
        }
        
        if (i == 0) {
            memo[i] = nums[0];
        } else {
            int robCurrent = nums[i] + robHelper(nums, i - 2, memo);
            int skipCurrent = robHelper(nums, i - 1, memo);
            memo[i] = Math.max(robCurrent, skipCurrent);
        }
        
        return memo[i];
    }
}

5.4. Complexity Analysis

  • Time Complexity : O(n) - Each subproblem solved once
  • Space Complexity : O(n) - For recursion stack and memoization array

6. 📊 Solution Comparison

Solution Time Space Pros Cons
Standard DP O(n) O(n) Most intuitive, easy to understand Higher memory usage
Space Optimized O(n) O(1) Optimal space, efficient Slightly less intuitive
Recursive O(n) O(n) Natural problem expression Recursion overhead

7. 💡 Summary

For the House Robber problem:

  • Standard DP is recommended for learning and understanding the fundamental pattern
  • Space-optimized DP is best for interviews and production use with optimal performance
  • Recursive approach helps understand the problem's mathematical structure

The key insight is recognizing the optimal substructure - the solution at each step depends only on the solutions to the two previous subproblems.

In life as in dynamic programming, our current decisions are shaped by our past choices, and the optimal path forward often requires balancing immediate gains with long-term consequences.

相关推荐
纪莫4 分钟前
技术面:如何让你的系统抗住高并发的流量?
java·redis·java面试⑧股
龙山云仓7 分钟前
No131:AI中国故事-对话荀子——性恶论与AI约束:礼法并用、化性起伪与算法治理
大数据·人工智能·深度学习·算法·机器学习
夏鹏今天学习了吗15 分钟前
【LeetCode热题100(90/100)】编辑距离
算法·leetcode·职场和发展
spencer_tseng22 分钟前
Unlikely argument type for equals(): JSONObject seems to be unrelated to String
java·equals
爱敲代码的小鱼35 分钟前
事务核心概念与隔离级别解析
java·开发语言·数据库
芒克芒克42 分钟前
数组去重进阶:一次遍历实现最多保留指定个数重复元素(O(n)时间+O(1)空间)
数据结构·算法
小冷coding1 小时前
【Java】遇到微服务接口报错导致系统部分挂掉时,需要快速响应并恢复,应该怎么做呢?如果支付服务出现异常如何快速处理呢?
java·开发语言·微服务
星火开发设计1 小时前
二维数组:矩阵存储与多维数组的内存布局
开发语言·c++·人工智能·算法·矩阵·函数·知识
一个处女座的程序猿O(∩_∩)O1 小时前
Nacos 中的 Namespace 深度解析:实现多租户隔离的关键机制
java
HeisenbergWDG1 小时前
线程实现runnable和callable接口
java·开发语言