LeetCode 热题 HOT 100(P21~P30)

2024-03-24 22:36
文章标签 leetcode 100 热题 hot p30 p21

本文主要是介绍LeetCode 热题 HOT 100(P21~P30),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 系列文章: 

LeetCode 热题 HOT 100(P1~P10)-CSDN博客

LeetCode 热题 HOT 100(P11~P20)-CSDN博客

LeetCode 热题 HOT 100(P21~P30)-CSDN博客

LC48rotate_image

. - 力扣(LeetCode)

题目:

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

解法:

也是套路题,乍一看完全没思路,旋转到底要怎么弄?实际的解法是把旋转变成翻转的组合,比如这里顺时针旋转90度,相当于先上下翻转,再沿对角线翻转,针对翻转的代码就比较好写了。
 public void rotate(int[][] matrix) {final int row = matrix.length;final int col = matrix[0].length;//上下翻转for (int i = 0; i < row / 2; i++) {for (int j = 0; j < col; j++) {swap(matrix, i, j, row - i - 1, j);}}//对角线翻转for (int i = 0; i < row; i++) {for (int j = i + 1; j < col; j++) {swap(matrix, i, j, j, i);}}}private void swap(int[][] matrix, int rowIndex, int colIndex, int newRowIndex, int newColIndex) {int tmp = matrix[rowIndex][colIndex];matrix[rowIndex][colIndex] = matrix[newRowIndex][newColIndex];matrix[newRowIndex][newColIndex] = tmp;}

LC49group_anagrams

. - 力扣(LeetCode)

题目:

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。

字母异位词 是由重新排列源单词的所有字母得到的一个新单词。

示例 1:

输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]输出: [["bat"],["nat","tan"],["ate","eat","tea"]]

解法:

理解题目的意思有点费劲,实际就是由相同字母组成单词的集合,很自然的想到用HashMap 。

 public List<List<String>> groupAnagrams(String[] strs) {Map<String, List<String>> cache = new HashMap<>();for (String str : strs) {final char[] chars = str.toCharArray();Arrays.sort(chars);cache.computeIfAbsent(new String(chars), (k) -> new ArrayList<String>()).add(str);}return new ArrayList<>(cache.values());}

写出代码不难,关键是能否写的尽量简练。

LC53maximum_subarray

. - 力扣(LeetCode)

题目:

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

子数组是数组中的一个连续部分。

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。

解法:

一般这种最*** 的题目理论上都可以用动态规划,核心难点是动态数组的定义,很多时候动态数组定义好了,动态推导方程也能比较简单的推演出来。

动态数组:dp[i] 表示包含下标i的连续子数组最大和

动态方程:dp[i] = Max(i,dp[i-1]+i) 

比较好理解的,这里稍微解释下包含i的数组最大和,基本要看前一位最大和是否小于0,如果是负数带上前面的肯定更小,还不如自己玩(i),如果前面大于0,那么带上肯定更大。

public int maxSubArray(int[] nums) {int[] dp = new int[nums.length];dp[0] = nums[0];int max = dp[0];for (int i = 1; i < nums.length; i++) {dp[i] = Math.max(nums[i], dp[i - 1] + nums[i]);max = Math.max(max, dp[i]);}return max;}

因为i只跟i-1 有关,因此动态数组可以简化为单个变量,其实动态规划很多代码都可以简化为单个或多个变量,但是这样的话代码就不太好理解。

LC55jump_game

. - 力扣(LeetCode)

题目:

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

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

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

解法:

可能也算套路题,有思路之后很简单。其实就是每跳一步就记录当前能跳到的最远位置,然后一个个位置跳过去,判断当前记录最远位置能否到下一个。实际上也是动态规划的思路。

动态数组:dp[i] 表示在i位置时能跳到的最远下标

动态方程:dp[i] = max(dp[i-1],i+nums[i])

 public boolean canJump(int[] nums) {//表示能达到的最远距离int k = 0;for (int i = 0; i < nums.length; i++) {if (k < i) {return false;}k = Math.max(k, i + nums[i]);}//能抵达最后一块石头就okreturn true;}

这里将动态数组精简为单个变量。

LC56merge_intervals

. - 力扣(LeetCode)

题目:

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].

解法:

区间合并的问题,首先是排序,按照starti 排序。然后就是进行入队操作,在入队的时候跟队首元素进行比较,看下当前元素starti 是否大于队首元素的endi,如果大于说明需要开一个新的区间,如果小于那就加入当前区间。

public int[][] merge(int[][] intervals) {// 先按照区间起始位置排序Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]);// 遍历区间List<int[]> result = new ArrayList<>();for (int[] interval : intervals) {// 如果结果数组是空的,或者当前区间的起始位置 > 结果数组中最后区间的终止位置,// 则不合并,直接将当前区间加入结果数组。if (result.isEmpty() || interval[0] > result.get(result.size() - 1)[1]) {result.add(interval);} else {final int[] ints = result.get(result.size() - 1);ints[1] = Math.max(ints[1], interval[1]);}}return result.toArray(new int[0][]);}

注意合并的写法,需要取当前元素的endi 和队首元素的endi 的最大值,在这里踩过坑。

LC62unique_paths

. - 力扣(LeetCode)

题目:

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

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

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

解法:

因为每次只能向下或者向右移动一步,因此要走到右下角,上一步只能从下面下来,或者从左边过来。对每个位置来说也可以这么推断,这里动态数组定义比较直观dp[i,j] 就是走到坐标[i,j] 一共有多少路径。动态方程dp[i,j] = dp[i-1,j] + dp[i,j-1]  。这里还涉及到动态数组的初始化,第一列和第一排的走法只有1种。

 public int uniquePaths(int m, int n) {int[][] dp = new int[m][n];//初始化行列的情况for (int i = 0; i < m; i++) {dp[i][0] = 1;}for (int i = 0; i < n; i++) {dp[0][i] = 1;}for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[i][j] = dp[i - 1][j] + dp[i][j - 1];}}return dp[m - 1][n - 1];}

LC64minimum_path

. - 力扣(LeetCode)

题目:

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

解法:

这道题跟上一道类似,不同的是这里求最小和,其实走法是一样的,因为只能从上面或者左边过来。动态数组定义为当前位置的最小值,动态方程有所调整,dp[i,j]=min(dp[i-1,j],dp[j,i-1]) +nums[i,j] 。 

 public int minPathSum(int[][] grid) {final 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] = grid[i][0] + dp[i - 1][0];}for (int i = 1; i < n; i++) {dp[0][i] = grid[0][i] + dp[0][i - 1];}for (int i = 1; i < m; i++) {for (int j = 1; j < n; j++) {dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];}}return dp[m - 1][n - 1];}

这里有个优化,可以不用新增动态数组dp ,直接在原数组grid 上直接操作,这样能节省内存开销。

LC70climbing_stairs

. - 力扣(LeetCode)

题目:

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

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

解法:

经典的爬楼梯算法题,他可以用递归的方式,也可以使用动态规划的思路。这类题目乍一看没思路,实际跟上面机器人走路是一样,要么从前1个台阶过来,要么从前2个台阶过来。动态方程比较简单:dp[i] = dp[i-1]+dp[i-2] 。因为只涉及前2个值,可以用2个变量替代数组。

public int climbStairs(int n) {if (n < 3) {return n;}int one = 1;int two = 2;for (int i = 3; i <= n; i++) {int cur = one + two;one = two;two = cur;}return two;}

LC72edit_distance

. - 力扣(LeetCode)

题目:

给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数  。

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

解法:

差不多也是套路题,这道题目跟机器走路的思路类似,可以参考下面的图

dp[i][j] 表示wrod1 的前 i 个字符转换成word2 的前j个字段所用的最小操作数 。相当于求最后一个格子的值。有点复杂的地方在于第一行和第一列作为空串进行初始化,第一行的意思是空串 ‘’ 变成'ros'  所需的最小步骤。第一列同理,这样就初始化好了动态数组。这里的动态方程有点复杂,需要分情况判断:

  • 当 word1[i] == word2[j],dp[i][j] = dp[i-1][j-1];
  • 当 word1[i] != word2[j],dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1 ;
    • dp[i-1][j-1] 表示替换操作
    • dp[i-1][j] 表示删除操作
    • dp[i][j-1] 表示插入操作。
public int minDistance(String word1, String word2) {final int row = word1.length();final int col = word2.length();// 因为有初始行和初始列,所以这里长度+1int[][] dp = new int[row + 1][col + 1];for (int i = 0; i <= row; i++) {dp[i][0] = i;}for (int i = 0; i <= col; i++) {dp[0][i] = i;}for (int i = 0; i < row; i++) {for (int j = 0; j < col; j++) {if (word1.charAt(i) == word2.charAt(j)) {dp[i + 1][j + 1] = dp[i][j];} else {dp[i + 1][j + 1] = Math.min(Math.min(dp[i][j], dp[i][j + 1]), dp[i + 1][j]) + 1;}}}return dp[row][col];}

LC75sort_colors

. - 力扣(LeetCode)

题目:

给定一个包含红色、白色和蓝色、共 n 个元素的数组 nums ,原地对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。

我们使用整数 0、 1 和 2 分别表示红色、白色和蓝色。

必须在不使用库内置的 sort 函数的情况下解决这个问题。

解法:

套路题,需要了解思路。维护0,1,2的初始下标,其中0,1初始在0,2初始在len-1,然后迭代数组,对数组中的数字进行判断,并相应的移动下标。可以参考官方的讲解配图,比较好理解。

public void sortColors(int[] nums) {if (nums.length == 0) {return;}//定义几个下标,需要实现// all in [0, zero] = 0// all in (zero, i) = 1// all in (two, len - 1] = 2int zero = 0, cur = 0, two = nums.length - 1;while (cur <= two) {if (nums[cur] == 0) {swap(nums, zero, cur);zero++;cur++;} else if (nums[cur] == 1) {cur++;} else {swap(nums, cur, two);//注意 这个时候cur 不能移动,因为交换之后还要再判断下two--;}}}private void swap(int[] nums, int i, int j) {final int tmp = nums[i];nums[i] = nums[j];nums[j] = tmp;}

这篇关于LeetCode 热题 HOT 100(P21~P30)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/843003

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

【JavaScript】LeetCode:16-20

文章目录 16 无重复字符的最长字串17 找到字符串中所有字母异位词18 和为K的子数组19 滑动窗口最大值20 最小覆盖字串 16 无重复字符的最长字串 滑动窗口 + 哈希表这里用哈希集合Set()实现。左指针i,右指针j,从头遍历数组,若j指针指向的元素不在set中,则加入该元素,否则更新结果res,删除集合中i指针指向的元素,进入下一轮循环。 /*** @param

LeetCode:64. 最大正方形 动态规划 时间复杂度O(nm)

64. 最大正方形 题目链接 题目描述 给定一个由 0 和 1 组成的二维矩阵,找出只包含 1 的最大正方形,并返回其面积。 示例1: 输入: 1 0 1 0 01 0 1 1 11 1 1 1 11 0 0 1 0输出: 4 示例2: 输入: 0 1 1 0 01 1 1 1 11 1 1 1 11 1 1 1 1输出: 9 解题思路 这道题的思路是使用动态规划

LeetCode 第414场周赛个人题解

目录 Q1. 将日期转换为二进制表示 原题链接 思路分析 AC代码 Q2. 范围内整数的最大得分 原题链接 思路分析 AC代码 Q3. 到达数组末尾的最大得分 原题链接 思路分析 AC代码 Q4. 吃掉所有兵需要的最多移动次数 原题链接 思路分析 AC代码 Q1. 将日期转换为二进制表示 原题链接 Q1. 将日期转换为二进制表示 思路分析

【JavaScript】LeetCode:21-25

文章目录 21 最大子数组和22 合并区间23 轮转数组24 除自身以外数组的乘积25 缺失的第一个正数 21 最大子数组和 贪心 / 动态规划贪心:连续和(count)< 0时,放弃当前起点的连续和,将下一个数作为新起点,这里提供使用贪心算法解决本题的代码。动态规划:dp[i]:以nums[i]为结尾的最长连续子序列(子数组)和。 dp[i] = max(dp[i - 1]