力扣大厂热门面试算法题 - 动态规划

        爬梯子、跳跃游戏、最小路径和、杨辉三角、接雨水。每题做详细思路梳理,配套Python&Java双语代码, 2024.03.05 可通过leetcode所有测试用例。

目录

70. 爬楼梯

解题思路

完整代码

Python

Java

55. 跳跃游戏

解题思路

完整代码

Python

代码优化 

Java

64. 最小路径和

解题思路

完整代码

Python

Java

118. 杨辉三角

解题思路

完整代码

Python

Java

42. 接雨水

解题思路

完整代码

Python

Java


70. 爬楼梯

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?

示例 1:

输入:n = 2
输出:2
解释:有两种方法可以爬到楼顶。
1. 1 阶 + 1 阶
2. 2 阶

示例 2:

输入:n = 3
输出:3
解释:有三种方法可以爬到楼顶。
1. 1 阶 + 1 阶 + 1 阶
2. 1 阶 + 2 阶
3. 2 阶 + 1 阶

解题思路

这个问题是一个经典的动态规划问题,可以通过动态规划的方法来解决。思路如下:

  1. 定义状态:定义dp[i]表示到达第i阶楼梯有dp[i]种方法。
  2. 状态转移方程:到达第i阶楼梯可以从第i-1阶上来,也可以从第i-2阶上来。因此,dp[i] = dp[i-1] + dp[i-2]。
  3. 初始化:dp[0]=1(没有楼梯时我们认为有一种方法),dp[1]=1(只有一阶楼梯时只有一种方法)。
  4. 计算顺序:从第2阶楼梯开始计算直到第n阶。

完整代码

Python

class Solution:
    def climbStairs(self, n: int) -> int:
        if n <= 1:
            return 1
        dp = [0] * (n + 1)
        dp[0], dp[1] = 1, 1
        for i in range(2, n + 1):
            dp[i] = dp[i - 1] + dp[i - 2]
        return dp[n]

Java

public class Solution {
    public int climbStairs(int n) {
        if (n <= 1) {
            return 1;
        }
        int[] dp = new int[n + 1];
        dp[0] = 1;
        dp[1] = 1;
        for (int i = 2; i <= n; i++) {
            dp[i] = dp[i - 1] + dp[i - 2];
        }
        return dp[n];
    }
}

55. 跳跃游戏

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

示例 1:

输入:nums = [2,3,1,1,4]
输出:true
解释:可以先跳 1 步,从下标 0 到达下标 1, 然后再从下标 1 跳 3 步到达最后一个下标。

示例 2:

输入:nums = [3,2,1,0,4]
输出:false
解释:无论怎样,总会到达下标为 3 的位置。但该下标的最大跳跃长度是 0 , 所以永远不可能到达最后一个下标。

提示:

  • 1 <= nums.length <= 104
  • 0 <= nums[i] <= 105

解题思路

        要使用动态规划解决这个问题,我们可以定义一个状态数组dp,其中dp[i]表示能否到达数组中的第i个位置。动态规划的过程是从前向后逐步构建dp数组的值,直到最后一个元素。

具体步骤如下:

  1. 初始化:创建长度为nums.length的布尔数组dp,初始全部设为false。dp[0] = true,因为起始位置总是可达的。
  2. 状态转移:对于每一个位置i(i从1开始到nums.length - 1),遍历i之前的所有位置j(j从0到i-1),如果位置j是可达的(即dp[j] == true)并且从位置j跳跃的最大长度(nums[j])加上j的位置能够达到或超过i(即j + nums[j] >= i),那么位置i也是可达的,设置dp[i] = true。
  3. 返回值:最后,返回dp数组的最后一个值,即dp[nums.length - 1],表示是否能够到达最后一个下标。

完整代码

Python

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        dp = [False] * len(nums)
        dp[0] = True  # 起始位置总是可达的
        for i in range(1, len(nums)):
            for j in range(i):
                # 如果j是可达的,并且从j可以跳到i或更远,则将i标记为可达
                if dp[j] and j + nums[j] >= i:
                    dp[i] = True
                    break  # 找到一个可达的j就足够了,无需继续查找
        return dp[-1]  # 返回是否可以到达最后一个位置
代码优化 

       这个动态规划解法可通过142个测试用例,有的会因为时间过长失败,可以通过优化来减少其时间复杂度。原始的解法中,我们使用了嵌套循环,导致时间复杂度为O(n^2)。优化的思路是利用贪心算法的原理来更新一个变量,记录当前能够到达的最远距离,这样可以避免内层的循环,将时间复杂度降低到O(n)。

class Solution:
    def canJump(self, nums: List[int]) -> bool:
        maxReach = 0  # 初始化最远可到达位置
        for i, jump in enumerate(nums):
            if i > maxReach:  # 如果当前位置i超出了之前可达的最远距离maxReach,则无法到达i
                return False
            maxReach = max(maxReach, i + jump)  # 更新可到达的最远位置
            if maxReach >= len(nums) - 1:  # 如果maxReach已经到达或超过最后一个位置,则可以到达
                return True
        return False  # 如果遍历结束还没有返回True,则表示不能到达最后一个位置

Java

public class Solution {
    public boolean canJump(int[] nums) {
        boolean[] dp = new boolean[nums.length];
        dp[0] = true; // 初始化起点为可达
        for (int i = 1; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {
                // 如果j是可达的,并且从j可以跳到i或更远,则将i标记为可达
                if (dp[j] && j + nums[j] >= i) {
                    dp[i] = true;
                    break; // 找到一个可达的j就足够了,无需继续查找
                }
            }
        }
        return dp[nums.length - 1]; // 返回是否可以到达最后一个位置
    }
}

64. 最小路径和

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

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

示例 1:






输入:grid = [[1,3,1],[1,5,1],[4,2,1]]
输出:7
解释:因为路径 1→3→1→1→1 的总和最小。

示例 2:

输入:grid = [[1,2,3],[4,5,6]]
输出:12

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 200
  • 0 <= grid[i][j] <= 200

解题思路

        对于“最小路径和”这个问题,我们同样可以使用动态规划的方法来解决。这个问题的目标是找到从左上角到右下角的路径,使得路径上的数字总和为最小。

解题思路如下:

  1. 定义状态dp[i][j]表示从左上角到达点(i, j)的最小路径和。
  2. 状态转移方程:到达点(i, j)的路径可以从上方(i-1, j)或左方(i, j-1)来,因此dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])。需要特别注意边界条件,即当ij为0时,只有一条路径可走。
  3. 初始化dp[0][0] = grid[0][0],即起点的最小路径和就是其自身的值。对于第一行和第一列的其他元素,因为它们只能从一个方向来(要么是上边,要么是左边),所以可以直接累加。
  4. 计算顺序:从左上角开始,逐行或逐列填充dp数组,直到右下角。
  5. 返回值dp数组右下角的值,即dp[m-1][n-1],代表了从左上角到右下角的最小路径和。

完整代码

Python

class Solution:
    def minPathSum(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        dp = [[0] * n for _ in range(m)]
        dp[0][0] = grid[0][0]
        
        for i in range(1, m):
            dp[i][0] = dp[i-1][0] + grid[i][0]
        for j in range(1, n):
            dp[0][j] = dp[0][j-1] + grid[0][j]
            
        for i in range(1, m):
            for j in range(1, n):
                dp[i][j] = grid[i][j] + min(dp[i-1][j], dp[i][j-1])
                
        return dp[-1][-1]

Java

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

118. 杨辉三角

给定一个非负整数 numRows生成「杨辉三角」的前 numRows 行。

在「杨辉三角」中,每个数是它左上方和右上方的数的和。

示例 1:

输入: numRows = 5
输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

示例 2:

输入: numRows = 1
输出: [[1]]

提示:

  • 1 <= numRows <= 30

解题思路

        生成杨辉三角的过程可以通过动态规划的方法来实现。每一行的数字是基于上一行的数字计算得来的,具体规则是:每一行的第一个和最后一个数字都是1,对于其中的其他数字,即第i行的第j个数字(行列均从0开始计数),可以通过上一行的第j-1个数字和第j个数字之和获得,即triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]

解题思路如下:

  1. 初始化:初始化一个列表triangle来存储整个杨辉三角。
  2. 外层循环:从第0行遍历到第numRows-1行。
    • 每一行初始化一个列表row,首个元素设为1(因为每行的开始都是1)。
  3. 内层循环:从第1个元素遍历到当前行的倒数第二个元素(因为每行的最后一个元素也是1,已经确定)。
    • 根据triangle[i][j] = triangle[i-1][j-1] + triangle[i-1][j]的规则计算当前位置的元素,并添加到当前行列表row中。
  4. 行尾处理:在每一行的最后添加1(每行的结束都是1)。
  5. 将当前行添加到杨辉三角中:将构建好的当前行row添加到triangle中。
  6. 返回结果:返回triangle

完整代码

Python

class Solution:
    def generate(self, numRows: int) -> List[List[int]]:
        triangle = []
        
        for i in range(numRows):
            row = [None for _ in range(i + 1)]  # 初始化当前行
            row[0], row[-1] = 1, 1  # 每行的开始和结束都是1
            
            for j in range(1, len(row) - 1):  # 计算中间的值
                row[j] = triangle[i-1][j-1] + triangle[i-1][j]
                
            triangle.append(row)  # 将当前行添加到杨辉三角中
        
        return triangle

Java

public class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> triangle = new ArrayList<List<Integer>>();
        
        for (int i = 0; i < numRows; i++) {
            List<Integer> row = new ArrayList<Integer>();
            
            for (int j = 0; j <= i; j++) {
                if (j == 0 || j == i) {  // 每行的开始和结束都是1
                    row.add(1);
                } else {
                    row.add(triangle.get(i-1).get(j-1) + triangle.get(i-1).get(j));  // 计算中间的值
                }
            }
            
            triangle.add(row);  // 将当前行添加到杨辉三角中
        }
        
        return triangle;
    }
}

42. 接雨水

给定 n 个非负整数表示每个宽度为 1 的柱子的高度图,计算按此排列的柱子,下雨之后能接多少雨水。

示例 1:

输入:height = [0,1,0,2,1,0,1,3,2,1,2,1]
输出:6
解释:上面是由数组 [0,1,0,2,1,0,1,3,2,1,2,1] 表示的高度图,在这种情况下,可以接 6 个单位的雨水(蓝色部分表示雨水)。 

示例 2:

输入:height = [4,2,0,3,2,5]
输出:9

提示:

  • n == height.length
  • 1 <= n <= 2 * 10^4
  • 0 <= height[i] <= 10^5

解题思路

        接雨水问题可以通过动态规划来解决。核心思想是计算每个柱子上方能接多少雨水,这取决于该柱子左右两侧最高柱子的高度。具体来说,某个位置能接的雨水量,等于该位置左侧最高柱子和右侧最高柱子中较矮的一个的高度减去当前柱子的高度。

动态规划的步骤如下:

  1. 计算每个位置的左侧最大高度:遍历一次高度数组height,计算每个位置左侧的最大高度,存储在数组leftMax中。
  2. 计算每个位置的右侧最大高度:再次遍历高度数组height,但这次是从右向左遍历,计算每个位置右侧的最大高度,存储在数组rightMax中。
  3. 计算每个位置上方能接的雨水量:遍历每个位置,使用min(leftMax[i], rightMax[i]) - height[i]来计算每个位置上方能接的雨水量。如果这个值是负数,则说明在该位置不会积水,因此将其视为0。
  4. 求和:将每个位置上方能接的雨水量相加,得到总的接雨水量。

完整代码

Python

class Solution:
    def trap(self, height: List[int]) -> int:
        if not height:
            return 0

        n = len(height)
        leftMax = [0] * n
        rightMax = [0] * n
        water = 0

        leftMax[0] = height[0]
        for i in range(1, n):
            leftMax[i] = max(leftMax[i-1], height[i])
        
        rightMax[n-1] = height[n-1]
        for i in range(n-2, -1, -1):
            rightMax[i] = max(rightMax[i+1], height[i])
        
        for i in range(n):
            water += min(leftMax[i], rightMax[i]) - height[i]
        
        return water

Java

public class Solution {
    public int trap(int[] height) {
        if (height == null || height.length == 0) {
            return 0;
        }

        int n = height.length;
        int[] leftMax = new int[n];
        int[] rightMax = new int[n];
        int water = 0;

        leftMax[0] = height[0];
        for (int i = 1; i < n; i++) {
            leftMax[i] = Math.max(leftMax[i-1], height[i]);
        }

        rightMax[n-1] = height[n-1];
        for (int i = n-2; i >= 0; i--) {
            rightMax[i] = Math.max(rightMax[i+1], height[i]);
        }

        for (int i = 0; i < n; i++) {
            water += Math.min(leftMax[i], rightMax[i]) - height[i];
        }

        return water;
    }
}

------------------------------

总结不易。看到这了,觉得有用的话点个赞吧。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/432021.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【kubernetes】关于k8s集群的存储卷

目录 一、存储卷的分类 二、empty存储卷以及特点 三、hostpath存储卷以及特点 四、nfs存储卷以及特点 五、pvc存储卷 查看pv的定义 查看pvc的定义 实操&#xff1a;静态创建pv的方式 实现pvc存储卷 步骤一&#xff1a;先完成nfs的目录共享&#xff0c;需要准备不同的目…

为PDF创建目录(侧边栏目录)

通过可以新建书签的pdf阅读器。 知云翻译&#xff1a;可以新建书签和子书签。 Adobe Acrobat&#xff1a;只能新建书签&#xff0c;不能建立子书签。

思维调试:为什么FormatMessage提示找不到资源?

在不调试的情况下解决下面的问题&#xff0c;说明你的思维调试能力又进阶了。 问题 我在调用 FormatMessage 函数加载一个插入的资源字符串&#xff0c;由于某种未知的原因&#xff0c;它没能按预期那样工作。 我要加载的字符串类似于这样的 “Blah blah blah %1. Blah blah …

MongoDB获评2023年Gartner®云数据库管理系统“领导者”

MongoDB 很荣幸在《2023 年 Gartner 云数据库管理系统 (CDBMS) 魔力象限》报告中被评为领导者。我们相信这一成就让 MongoDB 成为唯一一家连续两年斩获“领导者”称号的纯应用程序数据库服务提供商。 社区及开发者数据平台用户的需求一向是 MongoDB 关注的重点&#xff0c;而这…

《低代码平台开发实践:基于React》读书心得与实战体验

低代码平台开发实践标题 &#x1f3ac; 江城开朗的豌豆&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 &#x1f4dd; 个人网站 :《 江城开朗的豌豆&#x1fadb; 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 &#x1f4d8; 一、引…

2024年最新苹果cms MXoneV10 10.8版本模板独家

2024年最新苹果cms MXoneV10 10.8版本模板独家 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88891237 更多资源下载&#xff1a;关注我。

【Python】Python注册微服务到nacos

Python注册微服务到Nacos 1.Nacos部署 github 的nacos项目的发布页&#xff08;Releases alibaba/nacos GitHub &#xff09;&#xff0c;选择所要下载的nacos版本&#xff0c;在nacos下方的assets中选择安装包进行下载。 解压nacos安装包到指定目录。 tar -zxvf nacos-ser…

Flutter图片内存占用过大问题

图片(Image)加载原理&#xff1a; Image &#xff1a; 显示图⽚的Widget&#xff0c;通过ImageState管理ImageProvider的⽣命周期。 ImageProvider&#xff1a; 图⽚的抽象概念。 根据Image创建实例时调用的工厂方法的不同&#xff08;Image.network或者Image.assetImage&#…

CSS标准文档流与脱离文档流,分享一点面试小经验

大厂面试真题整理 CSS&#xff1a; 1&#xff0c;盒模型 2&#xff0c;如何让一个盒子水平垂直居中&#xff1f; 3&#xff0c;css 优先级确定 4&#xff0c;解释下浮动和它的工作原理&#xff0c;清除浮动的方法&#xff1f; 5&#xff0c;CSS隐藏元素的几种方法 6&#xff0…

浅谈神经网络的正则化技术

神经网络的正则化技术是一组用于减少过度拟合(overfitting)的方法,其中过度拟合是指模型在训练集上表现很好,但在测试集上表现不佳的情况。这些技术有助于提高模型的泛化能力,使其在未见过的数据上表现更好。 以下是几种常见的神经网络正则化技术: Dropout: Dropout …

Python 多线程编程实战:threading 模块的最佳实践

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站AI学习网站。 目录 前言 线程的创建 1. 继承 threading.Thread 类 2. 使用 threading.Thread 对象 线程的同步 使用锁 线程的通信…

如何开发分销商城小程序呢_打造分销利器

打造分销利器&#xff0c;揭秘如何开发一款成功的分销商城小程序 在移动互联网时代&#xff0c;小程序以其轻便、快捷的特点&#xff0c;成为了连接用户与服务的桥梁。其中&#xff0c;分销商城小程序更是受到了广大商家的青睐。那么&#xff0c;如何开发一款成功的分销商城小…

PCM会重塑汽车OTA格局吗(1)

目录 1.汽车OTA概述 2.ST如何考虑OTA&#xff1f; 2.1 Stellar四大亮点 2.2 PCM技术视角下的OTA 3.小结 1.汽车OTA概述 随着智能网联汽车的飞速发展&#xff0c;汽车OTA也越来越盛行&#xff1b; 目前来讲OTA分为FOTA和SOTA(Software-over-the-air)两种&#xff0c;区别…

解决win10串口一直被占用

目录 问题描述解决方法 问题描述 串口设备一直被占用&#xff0c;换串口也没有用&#xff0c;永远都是串口正在被使用&#xff0c;甚至换硬件设备也不行&#xff0c;都快烦死了 解决方法 输入这个&#xff1a; 删除这个玩意&#xff0c;计算机\HKEY_LOCAL_MACHINE\SYSTEM\Cu…

Reqable爬虫抓包工具(国产网络调试工具)

官网界面截图&#xff1a; 官网地址&#xff1a;https://reqable.com/zh-CN/windows/ 历史由来&#xff1a; Reqable的前身是HttpCanary&#xff08;一款Android平台应用程序&#xff09;&#xff0c;但是国内开发者推翻了所有的技术栈&#xff0c;并用C和Flutter重写&#x…

Tensorflow2.0笔记 - 计算梯度

本笔记主要记录tf.GradientTape和tf.gradient的用法 import tensorflow as tf import numpy as nptf.__version__#要计算梯度的所有参数计算过程必须放到gradient tape中 #with tf.GradientTape as tape: w tf.constant(1.) x tf.constant(2.)with tf.GradientTape() as tap…

在线部署ubuntu20.04服务器,安装jdk、mysql、redis、nginx、minio

查看服务器版本为20.04 lsb_release -a服务器初始账号密码 sxd / 123456 首先,更改自身密码都输入123456 sudo passwd 创建最高权限root账号&#xff0c;密码为 123456 su root 更新源列表 sudo apt-get update 安装 openssh-server和vim&#xff0c;途中输入y sudo ap…

46、Numpy手推共空间模式CSP,用于脑电EEG信号分类

一、Numpy实现CSP公式及对应的代码 CSP全部流程&#xff1a; 1、CSP先将数据按照类别分类&#xff0c;两类数据可分为E1、E2 2、计算分类后的原始数据的协方差矩阵&#xff1a; 方差矩阵&#xff1a; C协方差矩阵&#xff0c;E原始EEG信号&#xff0c;trace求迹 实现代码&a…

使用java的Stream流进行Collectors.groupingBy分组后生成Map,对Map进行删除原集合是否会发生改变

在Java中&#xff0c;当我们使用Collectors.groupingBy方法对集合进行分组操作时&#xff0c;生成的新映射&#xff08;Map&#xff09;是基于原始集合&#xff08;allItems&#xff09;的数据结构和内容创建的。这意味着&#xff0c;如果你更改了新的映射allItemMap中的值&…

xss.haozi.me:0X12

</script> <script>alert(1)\</script>