3.26(动态规划)

3.26

Lc.198.打家劫舍

你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。

给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。

class Solution {
    public int rob(int[] nums) {
        int n = nums.length;
        int []dp = new int[n];
        dp[0] = nums[0];
        if(n == 1)
            return dp[0];
        dp[1] = Math.max(nums[0],nums[1]);//注意这里不要数组越界,之前放在if上面就报错了
        for(int i = 2;i <= n-1;i++){
            dp[i] = Math.max(dp[i-2] + nums[i],dp[i-1]);
        }
        return dp[n-1];
    }
}

Lc.740.删除并获得点数

给你一个整数数组 nums ,你可以对它进行一些操作。

每次操作中,选择任意一个 nums[i] ,删除它并获得 nums[i] 的点数。之后,你必须删除 所有 等于 nums[i] - 1 和 nums[i] + 1 的元素。

开始你拥有 0 个点数。返回你能通过这些操作获得的最大点数。

  • error2
class Solution {
    public int deleteAndEarn(int[] nums) {
        int maxVal = 0;
        for (int val : nums) {
            maxVal = Math.max(val, maxVal);
        }//1.Java增强for循环,得到最大数作为数组长度
        int[] sum = new int[maxVal + 1];
        for (int val : nums) {
            sum[val] += val;
        }//2.下标为val的数是val的点数,于是就转化为打家劫舍题,按顺序是因为相邻的两个要被删除
        return rob(sum);
    }

    public int rob(int[] nums){
        int length = nums.length;
        int first = nums[0];
        if (length == 1){
            return first;
        }
        int second = Math.max(nums[0], nums[1]);
        for (int i = 2;i < length; i++){
            int temp = second;
            second = Math.max(first + nums[i], second);
            first = temp;
        }
        return second;
    }
}

Lc.62.不同路径

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。

问总共有多少条不同的路径?

  • 二维数组版
class Solution {
    public int uniquePaths(int m, int n) {
        int[][] f = new int[m][n];
        for (int i = 0; i < m; ++i) {
            f[i][0] = 1;
        }
        for (int j = 0; j < n; ++j) {
            f[0][j] = 1;
        }
        for (int i = 1; i < m; ++i) {
            for (int j = 1; j < n; ++j) {
                f[i][j] = f[i - 1][j] + f[i][j - 1];
            }
        }
        return f[m - 1][n - 1];
    }
}
  • 滚动数组版(节省空间复杂度)
class Solution {
    public int uniquePaths(int m, int n) {
        int[] f = new int[n];
        for (int i = 0; i < n; i++){
            f[i] = 1;
        }
        for (int i = 1;i < m; i++){
            for (int j = 1; j < n; j++){
                f[j] += f[j-1];//下一行的数等于上一行加上左边的
            }
        }
        return f[n - 1];
    }
}

Lc.64.最小路径和

给定一个包含非负整数的 *m* x *n* 网格 grid ,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。

说明:每次只能向下或者向右移动一步。

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length;
        int n = grid[0].length;
        int[][] f = new int[m][n];
        f[0][0] = grid[0][0];//起点初始化
        for (int i = 1; i < m; i++){
            f[i][0] = grid[i][0] + f[i-1][0];
        }
        for (int j = 1; j < n; j++){
            f[0][j] = grid[0][j] + f[0][j-1];
        }
        for (int i = 1; i < m; i++){
            for (int j = 1; j < n; j++){
                int dp = Math.min(f[i-1][j], f[i][j-1]);
                f[i][j] = dp + grid[i][j];
            }
        }
        return f[m - 1][n - 1];
    }
}

Lc.63.不同路径2

给定一个 m x n 的整数数组 grid。一个机器人初始位于 左上角(即 grid[0][0])。机器人尝试移动到 右下角(即 grid[m - 1][n - 1])。机器人每次只能向下或者向右移动一步。

网格中的障碍物和空位置分别用 10 来表示。机器人的移动路径中不能包含 任何 有障碍物的方格。

返回机器人能够到达右下角的不同路径数量。

测试用例保证答案小于等于 2 * 109

  • 二维数组
    • error1
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int[][]f = new int[m][n];
        if (obstacleGrid[0][0] == 1|| obstacleGrid[m-1][n-1] == 1){
            return 0;//注意障碍物在起终点的情况
        }
        for (int i = 0; i < m && obstacleGrid[i][0] == 0; i++){
            f[i][0] = 1;
        }
        for (int j = 0; j < n && obstacleGrid[0][j] == 0; j++){
            f[0][j] = 1;
        }
        for (int i = 1; i < m; i++){
            for (int j =1; j < n; j++){
                f[i][j] = obstacleGrid[i][j] == 0 ? f[i-1][j] + f[i][j-1] : 0;//1.相当于if判断语句,是则执行前者,非则障碍物为0,即路径为0
            }
        }
        return f[m-1][n-1];
    }
}
  • 滚动数组
    • error2
class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;
        int []f = new int[n];
        for (int i = 0; i < n && obstacleGrid[0][i] == 0; i++){
            f[i] = 1;//1.第一行遇到障碍物就跳出循环,障碍物后路径都为0,不要误解为循环还能继续执行
        }
        for (int i = 1; i < m; i++){
            for (int j = 0; j < n; j++){
                if (obstacleGrid[i][j] == 1){
                    f[j] = 0;
                }
                else if (j != 0){
                    f[j] += f[j - 1];//2.判断j大于0,防止数组越界,不用担心第二行第一个没有值,因为是滚动数组,所以本身就存有第一行第一个的值
                }
            }
        }
        return f[n-1];
    }
}

Lc.120.三角形最小路径和

给定一个三角形 triangle ,找出自顶向下的最小路径和。

每一步只能移动到下一行中相邻的结点上。相邻的结点 在这里指的是 下标上一层结点下标 相同或者等于 上一层结点下标 + 1 的两个结点。也就是说,如果正位于当前行的下标 i ,那么下一步可以移动到下一行的下标 ii + 1

  • 二维数组
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int n = triangle.size();//list集合,用size求大小,即行数
        int[][] f = new int[n][n];
        f[0][0] = triangle.get(0).get(0);//首初始化
        for (int i = 1; i < n; i++){
            f[i][0] = f[i - 1][0] + triangle.get(i).get(0);//获得列表中第几行第几列
            for (int j = 1; j < i; j++){
                f[i][j] = Math.min(f[i - 1][j - 1], f[i - 1][j]) + triangle.get(i).get(j);
            }
            f[i][i] = f[i - 1][i - 1] + triangle.get(i).get(i);//尾初始化
        }
        int minTotal = f[n - 1][0];
        for (int i = 1; i < n; i++){
            minTotal = Math.min(minTotal, f[n - 1][i]);
        }
        return minTotal;
    }
}
posted @ 2026-03-26 22:59  shitnotme  阅读(7)  评论(0)    收藏  举报