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

        爬梯子、跳跃游戏、最小路径和、杨辉三角、接雨水。每题做详细思路梳理,配套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 1dp = [0] * (n + 1)dp[0], dp[1] = 1, 1for 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] = Truebreak  # 找到一个可达的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,则无法到达ireturn FalsemaxReach = max(maxReach, i + jump)  # 更新可到达的最远位置if maxReach >= len(nums) - 1:  # 如果maxReach已经到达或超过最后一个位置,则可以到达return Truereturn 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  # 每行的开始和结束都是1for 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) {  // 每行的开始和结束都是1row.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 0n = len(height)leftMax = [0] * nrightMax = [0] * nwater = 0leftMax[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;}
}

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

kafka高水位和leader epoch

什么是高水位&#xff1f; 高水位表示分区下副本消息到哪里是算正常提交的。比如如下图&#xff1a;leader副本写到8了&#xff0c;follower副本也写到8&#xff0c;那么这个8就代表要求的副本都写入了。消息到8这里才算提交成功&#xff0c;后面的15写入了也不算提交成功&…

【Leetcode 2673】使二叉树所有路径值相等的最小代价 —— 贪心法

2673. 使二叉树所有路径值相等的最小代价 给你一个整数n表示一棵 满二叉树 里面节点的数目&#xff0c;节点编号从1到n。根节点编号为1&#xff0c;树中每个非叶子节点i都有两个孩子&#xff0c;分别是左孩子2 * i和右孩子2 * i 1。 树中每个节点都有一个值&#xff0c;用下…

Vscode C/C++ 编译问题

1.最近开始在VScode上编写程序&#xff0c;遇到了以下的坑 This may occur if the process’s executable was changed after the process wasstarted, such as when installing an update. Try re-launching the application orrestarting the machine. 2.原因 这个不是由vs…

技术上的判断令你如何确定现货黄金卖出时机?

要讨论现货黄金卖出时机&#xff0c;我们首先要搞清楚一个问题&#xff0c;就是开仓和平仓的问题&#xff0c;如果投资者已经成了市场中的多头&#xff0c;那他寻找的卖出时机就是要找多头平仓的时机&#xff0c;如果投资者还没开仓&#xff0c;正在寻找市场中的开仓机会&#…

【RS】最新欧空局Sentinel-2卫星数据下载(哨兵1、2、3、5P、6系列)

之前分享过Sentinel2数据下载的方法&#xff0c;但是有粉丝反应欧空局的网站更新了&#xff0c;之前的网站已经不能用了。所以自己抽空研究了一下新版的欧空局网站&#xff0c;今天就和大家分享一下如何使用新版的欧空局网站下载哨兵系列的卫星数据&#xff0c;本文以Sentinel2…

c语言-大小写字母的转换

目录 方法一&#xff1a;库函数直接转换 1、toupper的测试代码 2、tolower的测试代码 方法二&#xff1a;通过修改ASCII码值转换 1、自己实现大写转小写 2、自己实现小写转大写 结语 前言&#xff1a; 在使用c语言写代码时&#xff0c;通常会遇到很多将大小写字母相互…

IP定位在公安部门的使用及其重要性

随着信息技术的迅猛发展&#xff0c;互联网已成为现代社会不可或缺的一部分。然而&#xff0c;与此同时&#xff0c;网络犯罪也呈现出日益猖獗的趋势&#xff0c;给社会治安带来了极大的挑战。在这样的背景下&#xff0c;IP定位技术在公安部门的应用显得尤为重要。本文将对IP定…

geoserver+mapbox-gl 离线部署矢量切片地图服务学习笔记

geoserver安装 geoserver的安装包可以在官网下载Download - GeoServer&#xff0c;想要选择版本点击Archived找到指定版本进行下载http://geoserver.org/download/ &#xff08;如果网络不稳定&#xff0c;也可以直接使用下面的下载地址&#xff09; geoserver-2.15.0.rar资…

手把手带你申请【Sora】内测资格,附申请提示词

自从OpenAI发布了Sora之后&#xff0c;由于其流畅的画面&#xff0c;极高的真实度的60秒超长视频&#xff0c;瞬间秒杀当前市面上所有的视频胜场模型。 附上体验地址&#xff1a;https://openai.com/research/video-generation-models-as-world-simulators 相信Sora发布之后也…

PRewrite: Prompt Rewriting with Reinforcement Learning

PRewrite: Prompt Rewriting with Reinforcement Learning 基本信息 2024-01谷歌团队提交到arXiv 博客贡献人 徐宁 作者 Weize Kong&#xff0c;Spurthi Amba Hombaiah&#xff0c;Mingyang Zhang 摘要 工程化的启发式编写对于LLM&#xff08;大型语言模型&#xff09;应…

uniapp 滑动页面至某个元素或顶部

直接上代码&#xff1a; uni.pageScrollTo({selector: #top, // 需要返回顶部的元素id或class名称duration: 300 // 过渡时间&#xff08;单位为ms&#xff09; }); 官方文档&#xff1a;

什么是云游戏?云游戏平台可以运行3A游戏吗?

对于不熟悉游戏行业的人来说&#xff0c;面对云游戏可能会有一个疑问——除了单机游戏&#xff0c;现在所有游戏不都是联网玩吗&#xff1f;云游戏和网络游戏有什么区别&#xff1f; 实际上&#xff0c;云游戏和传统网络游戏有着本质的不同。 传统网络游戏需要玩家先下载并在本…

工时管理软件:为什么企业需要工时跟踪?

工时跟踪对于企业经营来说&#xff0c;可能不是首要事项。工时跟踪有什么用&#xff1f; 管理学大师彼得德鲁克曾说过&#xff1a;If you can’t measure it, you can’t improve it&#xff08;如果无法衡量&#xff0c;就无法改进&#xff09;。企业经营也是同样道理&#x…

注解校验备忘

NotNull 可用于一切包装类型 NotEmpty 用于String类型&#xff0c;表示不为空&#xff0c;并且长度大于0 用于List集合&#xff0c;表示不为空&#xff0c;并且size大于0 NotBlank 只用于字符串&#xff0c;去除两端空格后&#xff0c;长度大于0 Min和Max 包含当前值&a…

基于Python dlib的人脸识别的上课考勤管理系统(V2.0)

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝30W、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

2024年Android开发陷入饱和,想拿高工资

前言 从16年毕业至今&#xff0c;就职过两家公司&#xff0c;大大小小项目做了几个&#xff0c;非常感谢我的两位老大&#xff0c;在我的android成长路上给予我很多指导&#xff0c;亦师亦友的关系。 从年前至今参加面试了很多公司&#xff0c;也收到了几家巨头的offer&#…

2024Java大厂面试真题,java高级开发面试经验

概述 毫无疑问&#xff0c;Spring Cloud是目前微服务架构领域的翘楚&#xff0c;无数的书籍博客都在讲解这个技术。不过大多数讲解还停留在对Spring Cloud功能使用的层面&#xff0c;其底层的很多原理&#xff0c;很多人可能并不知晓。因此本文将通过大量的手绘图&#xff0c;…

一次线上JVM GC 长暂停排查,加班搞了好久

给大家分享一篇我在知乎上看到的&#xff0c;针对长时间 GC 问题排查定位过程的文章。 最终原因定位到 swap 空间上&#xff0c;是我未曾设想过的角度&#xff0c;因为常规的 GC 问题&#xff0c;相当大一部分原因最终定位出来都是代码相关、流量相关、配置相关的&#xff0c;…

需求并行开发场景,如何高效发布

云布道师 微服务架构下&#xff0c;每个应用服务独立开发、独立发布&#xff0c;小步快跑&#xff0c;持续快速交付业务需求。多人协同开发同一个应用时&#xff0c;分支开发模式是一个适合的协同方案。该模式下一个需求或任务通常对应一个 feature 分支&#xff0c;多个需求一…

WSL2安装+深度学习环境配置

WSL2安装深度学习环境配置 1 安装WSL22 配置深度学习环境1.1 设置用户名、密码1.2 安装cuda修改WSL安装路径 1.3 安装Anaconda 参考&#xff1a;搭建Windows Linux子系统&#xff08;WSL2&#xff09;CUDA环境 参考&#xff1a;深度学习环境配置 WindowsWSL2 1 安装WSL2 WSL …