Leetcode 198,118打家劫舍,杨辉三角

题目描述

题目解答

对于这道题,我们可以把每一层看成一个数组,核心思路是一行一行地推:先把第一行 1 当作地基塞进去,然后从第 1 行开始往右推导每一行,每一行的新元素都只依赖上一行,这就是典型的"状态转移"------上一行是状态,新一行是结果。推新行时按 j 从左到右遍历,用三个分支判断当前位置怎么算:开头 j=0 时上一行没有左邻居,直接取 prelist.get(0)(恒为 1);结尾 j==prelist.size() 时已经走到上一行最右下标的下一位,没有右邻居可加,取 prelist.get(j-1)(也是 1);中间就是两个肩膀之和 prelist.get(j) + prelist.get(j-1)。

java 复制代码
class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> list = new ArrayList<>();
        // 地基:第 0 行就是 [1]
        List<Integer> inner = new ArrayList<>();
        inner.add(1);
        list.add(inner);

        // 从第 1 行开始往后逐行推,每一行只依赖上一行
        for (int i = 1; i < numRows; i++) {
            List<Integer> prelist = list.get(i - 1);
            List<Integer> curlist = new ArrayList<>();

            // 当前行有 i+1 个元素,下标 j 从 0 到 i
            for (int j = 0; j <= i; j++) {
                // 左边界:上一行没有 j-1 这个位置,直接拿 prelist.get(0) = 1
                if (j - 1 < 0) {
                    curlist.add(prelist.get(j));
                    continue;
                }
                // 右边界:j 已经超出上一行最后一个下标,没有右邻居,拿 prelist 末尾 = 1
                if (j == prelist.size()) {
                    curlist.add(prelist.get(j - 1));
                    continue;
                }
                // 中间位置:上一行左右两肩之和
                curlist.add(prelist.get(j) + prelist.get(j - 1));
            }
            list.add(curlist);
        }
        return list;
    }
}

2.题目描述

题目解答

1.递归+记录数组

对于这道题目有一个很重要的点就是:对于当前的每一户来说,只有两个状态:偷或者不偷,所以我们可以将这两种状态下的值进行比较,哪个情况下的值最大,那个就是当前的最优解,首先,我们可以使用递归的方式,由上到下进行问题的拆分。为了防止递归时对同一个位置进行重复计算,我们可以建立一个数组来保存每一个位置的最优解,当发现此处有值的时候,我们就可以直接拿出来使用,而不是进行第二次递归。

java 复制代码
class Solution {
    int[] memo;
   public int rob(int[] nums) {
        memo = new int[nums.length];
        Arrays.fill(memo, -1);
        return dfs(nums, nums.length - 1);
    }
    private int dfs(int[] nums, int i) {
        if (i < 0) return 0;
        if (memo[i] != -1) return memo[i];   // 算过直接拿
        if (i == 0) return memo[0] = nums[0];
        return memo[i] = Math.max(dfs(nums, i - 1), nums[i] + dfs(nums, i - 2));
    }

2.设置状态

既然我们知道了核心思想,所以我们可以直接放弃递归,只用两个值来代表前面的第一个和第二个的最优解。

java 复制代码
// dp[i] 表示前 i+1 间房子(0..i)能偷到的最大金额;本题只跟 dp[i-1]、dp[i-2] 有关,所以用滚动变量把空间压到 O(1)
class Solution {
    int[] memo;   // 这个字段没用上,多余的,可以删
    public int rob(int[] nums) {
        // 没有房子可偷 → 0
        if(nums.length==0) return 0;
        // 只有一间 → 不偷白不偷
        if(nums.length==1) return nums[0];

        int prev2=nums[0]; // dp[i-2]:只考虑前 1 间时的最大金额
        int prev1=Math.max(prev2,nums[1]);       // dp[i-1]:考虑前 2 间时,挑钱多的那间偷

        // 从第 3 间开始逐间决策:偷 i(则 i-1 不能偷,加上 prev2)还是不偷 i(保持 prev1)
        for(int i = 2;i<nums.length;i++){
           int cur = Math.max(nums[i]+prev2,prev1);
           prev2=prev1;     // 滚动:旧 dp[i-1] 变成新的 dp[i-2]
           prev1 = cur;     // 当前结果变成新的 dp[i-1]
        }
        return prev1;       // 最后一个滚动变量就是 dp[n-1],即答案
    }
}
相关推荐
LuminousCPP1 小时前
数据结构-排序(三):快速排序进阶|挖坑法、双指针交换与手动栈非递归实现
c语言·数据结构·笔记·算法·排序算法
数据知道2 小时前
国密算法实战——SM2/SM3/SM4 在国产系统中的应用
网络·算法·安全·网络安全·密码学·哈希算法
zander2582 小时前
LeetCode 128. 最长连续序列
数据结构·算法
linx2952 小时前
单元四 · 对称认知·上:内存与指针
c语言·开发语言·数据结构·嵌入式硬件·算法
午彦琳3 小时前
2026.9.11
数据结构·python·算法
302wanger4 小时前
蛋炒饭周刊 · 第 1 期(2026-09-07至2026-09-11)
算法
shehuiyuelaiyuehao4 小时前
算法43,外观数列,模拟算法+双指针
java·算法
alphaTao4 小时前
LeetCode 每日一题 2026/9/7-2026/9/13
算法·leetcode