leetcode
leetcode 2901 ~ 2950
打家劫舍

打家劫舍

难度:

标签:

题目描述

English description is not available for the problem. Please switch to Chinese.

代码结果

运行时间: 20 ms, 内存: 16.2 MB


/*
 * 思路:
 * 使用Java Stream API来实现同样的逻辑。由于Stream不适合直接用于修改数组,我们将使用递归结合Stream来计算最大偷窃金额。
 */
import java.util.stream.IntStream;
public class Solution {
    public int rob(int[] nums) {
        return IntStream.range(0, nums.length).map(i -> rob(nums, i, new int[nums.length])).max().orElse(0);
    }
    private int rob(int[] nums, int i, int[] memo) {
        if (i < 0) return 0;
        if (memo[i] != 0) return memo[i];
        int result = Math.max(rob(nums, i - 1, memo), nums[i] + rob(nums, i - 2, memo));
        memo[i] = result;
        return result;
    }
}

解释

方法:

这道题的题解采用了递归加备忘录的方法来求解。小偷有一个选择,他可以选择从当前的房子开始偷或者跳过一两个房子后再开始偷。基本的递归策略是:考虑当前位置c,小偷可以选择偷这个房子然后跳过下一个,直接从c+2开始或者从c+3开始(即不偷当前房子,也可能不偷下一个,但考虑后一个),或者不偷当前房子直接从c+1开始。结果是这些选择中可以偷到的最大金额。使用备忘录(cache)来存储已经计算过的结果,避免重复计算,提高效率。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
递归方法中,为什么选择从c+2或c+3开始而不是其他位置,如c+4或更远的位置?
在这个问题中,选择从c+2或c+3开始是基于问题的最优子结构。当小偷决定偷c位置的房子时,他必须跳过c+1位置的房子,因此下一个可能的房子是c+2。同时,考虑到可能跳过更多房子以获取最大收益,算法也探索了从c+3开始的情形。通常,不需要从c+4或更远的房子开始,因为这些情况已经被c+2和c+3的结果覆盖,即从c+2或c+3开始的递归调用会进一步探索从c+4开始的情况。
🦆
在递归函数中,参数`money`没有在函数体中使用,它的目的是什么?是否是多余的?
参数`money`在这个递归函数的实现中确实没有被使用,它可能是在设计函数时预留的,用于可能的功能扩展或错误地从另一个类似函数复制过来的。在当前的函数实现中,`money`是多余的,因为它没有参与到任何计算逻辑中。正确的做法应该是从函数的参数列表中移除它,以避免混淆和可能的性能损失。
🦆
备忘录`cache`中存储的是从当前位置开始能偷到的最大金额,那么如何确保计算时包含了所有可能的偷窃组合?
备忘录`cache`确保了计算效率通过存储已经计算过的结果,避免了重复计算。在`dfs`函数中,每次计算一个位置c时,都会考虑三种选择:只偷下一个房子的情况(c+1),偷当前房子与后面第二个房子的组合(c+2加当前房子),以及偷当前房子与后面第三个房子的组合(c+3加当前房子)。函数通过递归调用自身来探索所有这些选择,并使用`max`函数来比较这些选项,确保选出最大金额。因此,通过这种方式,`cache`确实存储了从每个位置开始,考虑所有可能组合后能偷到的最大金额。

相关问题