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

news2024/11/23 15:40:29

        爬梯子、跳跃游戏、最小路径和、杨辉三角、接雨水。每题做详细思路梳理,配套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;
    }
}

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

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

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

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

相关文章

LeetCode每日一题 二叉树的最大深度(二叉树)

题目描述 给定一个二叉树 root &#xff0c;返回其最大深度。二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3 示例 2&#xff1a; 输入&#xff1a;root [1,nul…

大摩突发:将推出比特币ETF

作者&#xff1a;秦晋 随着比特币ETF愈发火爆&#xff0c;华尔街另一家管理1.3万亿美元资产的大型经纪自营商「摩根士丹利」正在蠢蠢欲动&#xff0c;准备进军比特币ETF。 据彭博社数据显示&#xff0c;目前10只比特币现货ETF在上周三创下单日交易新纪录&#xff0c;成交量超过…

太惊艳了!多微信管理利器,让你事半功倍!

作为现代社交媒体的主要平台之一&#xff0c;微信在商务领域中扮演着重要的角色。为了提高我们的工作效率&#xff0c;微信管理系统应运而生。 这个系统可以同时登录多个微信账号&#xff0c;并进行统一管理。除了便捷的登录管理功能外&#xff0c;微信管理系统还提供了许多实…

优思学院|质量和企业的盈利能力有何关系?

质量和企业的盈利能力有何关系&#xff1f;三十年前&#xff0c;这个问题就已经被提出。当时的学者们研究了高质量产品如何带来更高的盈利。虽然这听起来像是老生常谈&#xff0c;但它的真理至今仍深深影响着我们的商业决策。 为了更直观地理解&#xff0c;一些学者绘制了以下…

Redis 核心面试题归纳

文章目录 RedisAOF 相关1. redis AOF 文件备份时&#xff0c;是使用的 write ahead log 的方式吗2. redis 开启AOF后的写入步骤3. redis AOF文件重写过程4.AOF 持久化策略 RDB 相关1.RDB 写入过程rdb 过程中&#xff0c;复制的页表是什么 Redis 主从同步1.PSYNC 和 SYNC 的区别…

Vue 前端开发 v-for和v-if两个指令不能混合使用

原由&#xff1a; 在进行项目开发的时候因为在一个标签上同时使用了v-for和v-if两个指令导致的报错。 提示错误&#xff1a;The undefined variable inside v-for directive should be replaced with a computed property that returns filtered array instead. You should no…

安装QT时,安装进程(qt.tools.perl)运行期间出现错误

安装QT时&#xff0c;安装进程(qt.tools.perl)运行期间出现错误 解决方法

小智浏览器助手

作为使用者来说&#xff0c;这个浏览器头痛的地方就是不能随意的切换地址&#xff0c;每次都要重新配置ini文件 再重新打开。 于是&#xff0c;我想了个办法&#xff0c;在使用前面加个能切换&#xff0c;维护地址的程序&#xff0c;让它来调用这个浏览器不就实现我的要求了&a…

【CSP考点回顾】前缀和数组

一、一维数组前缀和 前缀和算法是一种用于处理数组的技术&#xff0c;它可以快速计算任何连续子数组的和。适合在多次查询中需要求解多个范围和的情况。使用前缀和算法可以将每次求和的时间复杂度从 O(n) 降低到 O(1)。 前缀和的思想是创建一个新数组 A r r Arr Arr&#xff0…

kamailio转发电话到目的地,目的返回失败时再转给其他IP

按图中这样测试&#xff1a; A---->kamailio------->B B返回480等失败错误码&#xff08;非200 OK&#xff09;&#xff0c;能进入failure_route[TOVOICEMAIL]&#xff0c;但是t_relay_to_udp执行失败。 好吧&#xff0c;说是&#xff1a;在 failure_route 中处理的是…

干货!Python函数定义与调用

1.函数定义 函数主要有两部分组成&#xff1a;声明部分和实现部分 def 是 define的简写&#xff0c;表示定义的意思 函数名类似于变量名&#xff0c;遵守标识符命名规则&#xff0c;尽量做到见名知意 ():里面放的是参数列表&#xff0c;参数列表中的参数可以为空 函数体:表…

Claude3荣登榜首,亚马逊云科技为您提供先行体验!

Claude3荣登榜首&#xff0c;亚马逊云科技为您提供先行体验&#xff01; 个人简介前言抢先体验关于Amazon BedrockAmazon Bedrock 的功能 Claude3体验教程登录Amazon Bedrock试用体验管理权限详细操作步骤1.提交应用场景详细信息2.请求模型的访问权限3.请求成功&#xff0c;开始…

Windows下Golang开发环境的安装

以下是在Windows操作系统下安装Go语言环境&#xff08;Golang&#xff09;的步骤。 请注意&#xff0c;安装步骤可能因Go的版本更新而有所变化&#xff0c;以下教程适用于撰写本文时的最新稳定版。 1、下载Go语言安装包 打开Go语言的官方下载页面&#xff1a;https://golang.go…

MySQL高可用性攻略:快速搭建MySQL主从复制集群 !

MySQL高可用性攻略&#xff1a;快速搭建MySQL主从复制集群 &#xff01; MySQL基础知识&#xff1a;介绍MySQL数据库的基本概念和常用命令&#xff0c;如何创建数据库、表、用户和权限管理等。 MySQL安装教程&#xff1a;Centos7 安装MySQL5.7.29详细安装手册 MySQL数据类型&…

Python 过滤函数filter()详解

一、过滤函数定义 它用于对容器中的元素进行过滤处理。 二、 过滤函数语法 filter(function,iterable) 参数function&#xff1a;提供过滤条件的函数&#xff0c;返回布尔型 参数iterable: 容器类型数据 三、过滤函数的应用场景 1、筛选符合条件的元素 需求&#xff1a;在列表…

VMware安装Ubuntu(保姆级)

VMware安装Ubuntu&#xff08;保姆级&#xff09; 文章目录 VMware安装Ubuntu&#xff08;保姆级&#xff09;一、镜像下载二、开始安装①&#xff1a;创建一个新的虚拟机②&#xff1a;开始安装③&#xff1a;安装 ssh 服务 提示&#xff1a;以下是本篇文章正文内容&#xff0…

第1题:两数之和

题目内容&#xff1a; 给定一个整数数组 nums 和一个整数目标值 target&#xff0c;请你在该数组中找出 和为目标值 target 的那 两个 整数&#xff0c;并返回它们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中同一个元素在答案里不能重复出现。…

“比特币刚破6.9万又套牢”?超31万人爆仓11.5亿美元!后市将如何发展?

时隔846天&#xff08;2021年11月10日&#xff09;之久&#xff0c;比特币终于在昨晚最高触及69080美元&#xff0c;再度创下历史新高&#xff0c;引发社群一片感慨&#xff1a;比特币再不亏欠任何人&#xff01; 怎料&#xff0c;比特币刚站上历史高点就急速下挫&#xff0c;一…

Linux基础——进程控制

1. 进程创建 在这之前我们曾了解过进程创建&#xff08;详见进程初识&#xff08;二&#xff09;&#xff09;&#xff0c;我们在这里对fork函数做一些补充 其实对于父子进程来说&#xff0c;若是有一方试图修改数据时&#xff0c;会向物理内存中申请一份新空间&#xff0c;并…

list链表的创建,排序,插入, test ok

1. 链表的建立&#xff0c;打印 #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <stack> #include <iostream> #include <string.h> #include <string>using namespace std;struct node {int data;s…