- 博客(38)
- 收藏
- 关注
原创 【力扣刷题】【51-100】【动态规划】64. 最小路径和
64. 最小路径和1.动态规划本题与62. 不同路径、63. 不同路径 II的思路十分类似,依然可以方便的用动态规划的思想解决。究其本质,是因为更靠后的状态,其最优方案,取决于更靠前的两个状态,而与未来的状态无关,抓住这个性质,我们就能很快的理清楚状态转移方程。与前两题类似,维护一个数组dp[m][n]dp[m][n]dp[m][n],代表到达位置i,j的最小路径和。本题当前状态并非上方、左方数值之和,而是左方、上方更小的一个加上当前位置的数字,状态转移方程为:dp[i][j]=min(dp
2022-04-21 14:56:29 1003
原创 【力扣刷题】【51-100】【动态规划】63. 不同路径 II
63. 不同路径 II1.动态规划这类求方案数的问题,都有一个特点:全局的方案数,取决于子问题的方案数,就能往动态规划的方向上考虑。状态转移方式与62. 不同路径 类似,某个节点的方案数只要考虑上方与左方的方案数即可,只是这里多了一个障碍物的判断,如果某点是障碍物,那么到达此点的可行方案就是0。加上障碍物判断后,此题的规划方式和上题一样。class Solution {public: int uniquePathsWithObstacles(vector<vector<
2022-04-20 21:34:55 216
原创 【力扣刷题】【51-100】【动态规划】62. 不同路径
62. 不同路径1.动态规划本题容易联想到动态规划解法。我们维持一个dp[m][n]dp[m][n]dp[m][n]数组,其含义是从起点到达i,j位置有多少条最短路径。接下来我们分析一下规划过程中的状态:一个位置,只可能是从它上面、左面两个方向走来的,这一点的不同路径数就是上面一格的不同路径数+左边一格的不同路径数。即dp[i][j]=dp[i−1][j]+dp[i][j−1]dp[i][j]=dp[i-1][j]+dp[i][j-1]dp[i][j]=dp[i−1][j]+dp[i][
2022-04-20 20:48:01 275
原创 【力扣刷题】【1-50】【动态规划】45. 跳跃游戏 II
45. 跳跃游戏 II1.动态规划本题主流解法是利用贪心,每次跳跃到可能跳的最远的位置上,不断求局部最优,最终达到全局最优。在这里提供一种动态规划的思路:我们维持一个数组dp,dp[i]的意义是:到达位置i需要的最小跳跃数。初始状态:dp[0]=0,最开始我们就站在0。其余dp[i]是一个极大的数值,因为初始我们假设跳不到这些位置。状态更新:假设dp[i]可以跳n下,我们就更新dp[i+1]到dp[i+n],也就是dp[i]可以一次跳跃到达的位置。根据dp[i]的意义,可以分析
2022-04-20 15:00:58 2874
原创 【力扣刷题】【1-50】【动态规划】42. 接雨水
42. 接雨水1.动态规划如本题标记为困难,但如果掌握了动态规划的思想,本题十分简单。首先明确一个观点:如何装水。装水需要当前这一格的左、右都比当前高,才能装水,并且存在一个”木桶效应“,能装的水量,取决于左右两侧较矮的一侧。假设我们当前站在i格子的位置:i左边的所有柱子最高为A,i右边的所有柱子最高为B。并且i格子当下的柱子高为C;那么必须C<min(A,B)才有可能装水,装水量为min(A,B)-C;至此每个位置能装水的状态就分析完全了,只需要正反两次遍历求出我们需要
2022-04-20 14:20:17 108
原创 【力扣刷题】【1-50】【动态规划】32. 最长有效括号
32. 最长有效括号1.动态规划如果简单的暴力解法,时间复杂度为O(n3)是完成不了本题的数据量的,真正重要的解法是动态规划。首先分析规划中的状态有哪些:只有两个,前括号(与后括号);对于前括号结尾的状态,不难想到,前括号对于最终结果产生不了任何影响,因为括号的配对必须是以后括号为结尾。因此我们需要分析的状态只有后括号出现的时刻。某一位置i以后括号为结尾,对于状态转移方式进行一些分析:i-1位置上为前括号,说明此时产生了匹配,dp[i]在dp[i-2]的基础上多配对成功了一对:
2022-04-19 23:17:05 97
原创 【力扣刷题】【51-100】【动态规划】53. 最大子数组和
53. 最大子数组和1.动态规划最大连续子数组和是最经典的动态规划入门题。思路:我们思考一种一次遍历就解决子数组和的方案。假设我们站在某个数字nums[a]的位置,并且已经知道前面一个数字nums[a-1]为结尾的最大连续数组和sum[a-1]。那么对于以nums[a]为结尾的最大子数组和只有两个可能:1.在sum[a-1]的基础上加上nums[a];2.或者从nums[a]重新开头组成最大子数组;这却决于nums[a]+sums[a-1]与nums[a]哪个更大,这就是站在
2022-04-19 21:55:13 81
原创 【力扣刷题】2245. 转角路径的乘积中最多能有几个尾随零
2245. 转角路径的乘积中最多能有几个尾随零本题注意尾随零的求法:求出所有乘数中因子2的个数a,因子5的个数b,a和b的最小值就是尾随零的个数。思路:当一组数相乘时,尾随数的个数就是乘数中可以提取出10的个数;如果要乘出一个10,有两种乘积方法:2乘5和1乘10,但1乘10本质上还可以再分解成1乘2乘5;因此我们并不需要真的做乘法,本题大量的数据也不支持这么操作,而是需要统计所有出现过的乘数中,最多能组成多少对2和5;为了解决这个问题,我们计算出每个位置的2和5的个数,再统计出每个位
2022-04-18 21:53:48 130
原创 【力扣刷题】【1-50】【二分查找】33. 搜索旋转排序数组
33. 搜索旋转排序数组1.利用数组规律二分查找普通的二分查找要求必须是一个有序数组,但是会发现这里的数组进行了一个旋转,是两个有序数组的拼接,前面的数组的数值都大于后面这部分数组。此种解法是利用了数组的这样一个规律:每次将数组一分为二,一定至少有一个是有序的部分。我们每次都在这个有序的部分里二分查找。是否是有序数组的判断标志:nums[0]与nums[mid]比较,如果nums[mid]>=nums[0],则[0,mid]的部分是有序数组,否则[mid,n-1]的部分是有序数组。
2022-04-15 15:44:54 223
原创 【力扣刷题】【1-50】【快慢指针】31. 下一个排列
31. 下一个排列1.寻找规律,构造算法因为题目要求我们不使用额外空间,因此我们不能构造出所有序列并且排序,需要根据当前序列直接推断出结果。如果没有见过这样的题目,直接设计出优秀算法难度是比较大的,可以直接学一下题解中的优秀方法。如果不好理解力扣题解的描述,可以看看我下面的分析:本题需要我们根据构造序列的规律,构造出符合条件的序列。我们假设自己没见过任何相关算法,试着分析一下这个问题:假设给出的数字是123654,我们要怎么写出下一个比它大的序列?不难发现后面三个数字654是完全倒
2022-03-29 20:56:45 121
原创 【力扣刷题】【1-50】【快慢指针】27. 移除元素
27. 移除元素1.快慢指针和26. 删除有序数组中的重复项中的技巧一样,我们仍然可以用一快一慢两个指针来完成这个任务,快指针遍历元素,慢指针指向保存元素的位置。最坏情况下,快慢两个指针都完整的遍历了数组,共遍历了两次。(我们能否至多一次遍历就完成?)class Solution {public: int removeElement(vector<int>& nums, int val) { int slow=0,fast=0;
2022-03-29 14:40:31 159
原创 【力扣刷题】【1-50】【快慢指针】26. 删除有序数组中的重复项
26. 删除有序数组中的重复项1.快慢指针遇到删除元素的问题,应当想到快慢指针这一常用方法。同样应用快慢指针的场景还有,可以一起完成:判断链表中是否有环:141. 环形链表题解:141.环形链表判断链表是否是回文链表:234. 回文链表题解:234.回文链表快指针在前不断遍历元素到结束,慢指针用于记录最终结果。class Solution {public: int removeDuplicates(vector<int>& nums)
2022-03-29 11:46:50 728
原创 【力扣刷题】【1-50】【快慢指针】141. 环形链表
141. 环形链表1.快慢指针判断链表中是否有环,是快慢指针思想最为经典的应用。我们从不了解这种方法开始,试着分析一下判断链表是否有环的问题:如果链表中有环,从头节点开始遍历,永远走不到NULL,如果没有环,总是能走到NULL;但如果我们通过寻找NULL来判断是否有环,是一种难以控制的方法,因为无法知道链表长度,不知道什么时候该停下来遍历。那我们如果有两个指针呢?并且这两个指针每次遍历前进的步数,一个大,一个小,这就是我们说的快慢指针。这种结构其实也十分简单:如果没有环,快
2022-03-29 11:42:40 613
原创 【力扣刷题】【1-50】【快慢指针】234. 回文链表
234. 回文链表1.快慢指针本题可以使用笨办法,根据题解中提到的转换成数组判断是否是回文,是可以达到要求的。在这里记录一种很巧妙的方法:快慢指针,只需要一次遍历,不需要额外空间完成判断。快指针比慢指针多走一步,走到末尾时,慢指针恰好在链表中间。在慢指针前进过程中,我们就将慢指针走过的前半部分原地反转,并记录一个前半部分的头节点。此时,只需要再遍历半次,判断分开的前后两个链表是否相等即可。class Solution {public: bool isPalindrome(ListN
2022-03-29 11:09:48 1158
原创 【力扣刷题】【1-50】25. K 个一组翻转链表
25. K 个一组翻转链表1.模拟交换本题比较经典,建议多练习。如果是初学,建议在完成24. 两两交换链表中的节点,可以理解哑巴节点的作用,能理解链表操作的特性再练习。本题和两两反转链表的原理是相同的,但是需要做到任意K个反转,并且在不足K个的时候以正常顺序返回不足K个的这一部分。但是本题实现起来却有一定难度,这里提及解决链表问题的一个重要心得:大量设变量,能有效降低分析复杂度 。因为链表的结构,导致在解决问题时,会涉及大量的->的操作,往往在操作之后,原有的顺序结构发生了改变
2022-03-23 23:14:22 595
原创 【力扣刷题】【1-50】24. 两两交换链表中的节点
24. 两两交换链表中的节点1.迭代交换本题可以重复进行三次操作完成交换,具体操作如下图所示,是链表的基本操作,体现了链表结构的思维。class Solution {public: ListNode* swapPairs(ListNode* head) { ListNode* result=new ListNode(); result->next=head; ListNode* dummy=result; whi
2022-03-23 21:48:20 543
原创 【力扣刷题】【1-50】23. 合并K个升序链表
[23. 合并K个升序链表](https://leetcode-cn.com/problems/merge-two-sorted-lists/)1.顺序合并根据合并两个有序链表的策略,我们每次找出当前所有链表中头节点比较大的那一个,连接到结果中。时间复杂度主要来源于K个链表的查找,复杂度为O(K2N)。这种方法比较简单直接。class Solution {public: ListNode* mergeKLists(vector<ListNode*>& lists)
2022-03-23 15:08:39 647
原创 【力扣刷题】【1-50】22. 括号生成
22. 括号生成1.深度优先搜索本题官方题解的思路我总觉得有点der,我这里尝试用深度优先搜索的方式完成。搜索方式简单概括起来就是:试探性地加入左、右括号,在正好匹配时记录结果;并且在超出边界时结束搜索。我在这里设置了四个搜索的参数:num_left,这一步的左括号数量num_right,这一步的右括号数量num_left_before,这一参数是关键,和括号匹配中的栈相似,记录等待着被匹配的左括号数。s,当前的字符串结果每次试探性的加入左括号,等待匹配的左括号+1;再次试探
2022-03-22 15:13:06 469
原创 【力扣刷题】【1-50】21. 合并两个有序链表
21. 合并两个有序链表1.两指针迭代对于合并两个有序集合为一个大有序集合的问题,都可以在O(n)复杂度内,用两集合取头部比较后插入的方式,完成合并。class Solution {public: ListNode* mergeTwoLists(ListNode* list1, ListNode* list2) { ListNode* head=new ListNode(); ListNode* result =head; while(
2022-03-21 15:15:09 631
原创 【力扣刷题】【1-50】20. 有效的括号
20. 有效的括号1.栈模拟对于栈的使用,最为经典的应用场景就是括号匹配。遇到括号的前半部,就压入。遇到后半部,如果栈为空,说明多出了一个括号的后半部,返回错误;如果栈非空,弹出栈顶元素,判断与后半部是否匹配。遍历完输入字符串时,如果栈为空,说明匹配完成,否则返回错误。class Solution {public: bool isValid(string s) { stack<char> stk; for(int i=0;i<
2022-03-20 00:07:43 350
原创 【力扣刷题】【1-50】19. 删除链表的倒数第 N 个结点
19. 删除链表的倒数第 N 个结点1.简单模拟,计算链表长度如果知道链表的长度,以及倒数第几个节点需要删去,就可得知正数需要删除第几个节点。可以先遍历一次计算出长度,再删除相应节点。链表相应的题目,可以使用哑巴节点dummy,避免头节点为空的讨论问题,无论何种情况,只需要dummy->next就能正确的返回结果。时间复杂度O(N)。class Solution {public: ListNode* removeNthFromEnd(ListNode* head,
2022-03-19 23:23:26 264
原创 【力扣刷题】【1-50】18. 四数之和
18. 四数之和1.双指针法和前面的求和题目相似,这里我们用双指针法降低算法复杂度,从O(n4)到O(n3)。4个移动指针,三重遍历,在第三重使用双指针。双指针法本身并不复杂,在这里关键是我们要做好剪枝 ,才是优秀的双指针方法。剪枝1:去除重复元素,四个指针,每次移动之后都要和前一个数值比较,避免重复元素参与比较;剪枝2:去除绝对不可能得到结果的位置:确定ind1后,如果ind1+ind1后面三个元素已经>target,那后面的结果必然也大于target,跳出循环;同
2022-03-14 16:05:14 819
原创 【力扣刷题】【1-50】17. 电话号码的字母组合
17. 电话号码的字母组合1.回溯回溯算法类似于枚举,不断尝试性的搜索,发现当前解不满足条件,就向前一步回退,搜索其他的可能性。第一次看到这个题目可能不一定会想到**“回溯”,而是可能第一反应是“遍历”** ,这一题其实是一种更为简单的遍历,每次遍历的结果都是合格的结果,不需要排除掉结果。class Solution {public: vector<string> result; string now_s,digits2; vector<str
2022-03-14 14:43:46 65
原创 【力扣刷题】【1-50】16. 最接近的三数之和
16. 最接近的三数之和1.双指针法本题和15. 三数之和 相似,可以使用双指针法在O(n2)内解决问题,建议先完成15. 三数之和 。因为本题不需要保留可能结果的数字序列,只需要返回最符合条件的和,所以在和等于target的时候可以直接退出。也可以利用去除重复元素的方式减小遍历计算次数。class Solution {public: int threeSumClosest(vector<int>& nums, int target) { s
2022-03-14 13:31:43 77
原创 【力扣刷题】【1-50】15. 三数之和
15. 三数之和1.双指针法如果采取暴力遍历,需要三重循环,时间复杂度为O(n3);我们这里使用双指针法:虽然有三个数字需要同时遍历,但我们可以利用数组排序后的性质,减小第二和第三个数组的时间复杂度:首先将数组递增排序;指针ind1不断从头到尾遍历,如果碰到nums[ind1]==nums[ind1-1]的情况,说明碰到了重复元素,直接跳过;指针ind2位于ind+1,指针ind3=n-1位于尾部,在每次遍历中,我们只移动ind2和ind3;因为数组是递增的,如果三数之
2022-03-12 10:57:20 1649
原创 【力扣刷题】【1-50】14. 最长公共前缀
14. 最长公共前缀1.纵向遍历纵向遍历就能完成任务,分别比较每个字符串的第0,1,2…位,是比较符合直觉的解法。class Solution {public: string longestCommonPrefix(vector<string>& strs) { string result; int max_len=INT_MAX; for(int i=0;i<strs.size();i++){
2022-03-11 20:47:05 242
原创 【力扣刷题】【1-50】13. 罗马数字转整数
13. 罗马数字转整数1.直接模拟本体比较简单,可以根据输入直接模拟;class Solution {public: int romanToInt(string s) { int result=0; for(int i=0;i<s.size();i++){ if(s[i]=='I'){ if(i+1<s.size()&&s[i+1]=='V'){result+=4;i+
2022-03-11 20:34:01 101
原创 【力扣刷题】【1-50】12. 整数转罗马数字
12. 整数转罗马数字1.直接模拟可以根据罗马数字的转换规则直接进行模拟,转换规则可以这样概括:依次从1000,500,100,50,10,5,1中选出一个最大值,转换成对应字母,需要特殊处理900,400,90,40,9,4;对应代码如下:class Solution {public: string intToRoman(int num) { string result; while(num){ // cout<
2022-03-11 17:16:05 61
原创 【力扣刷题】【1-50】11. 盛最多水的容器
11. 盛最多水的容器1.暴力枚举最容易想到直接暴力枚举,会进行Cn2C_{n}^{2}Cn2 次枚举,面积运算公式为$S=(r-l)*min( h[l],h[r] ) $、时间复杂度O(n2);这里的代码会超时,但是会帮助我们下面对于双指针的理解。如下图,以有八根木棍为例,事实上我们只进行了(8*8)/2次的计算.class Solution {public: int maxArea(vector<int>& height) {
2022-03-11 15:20:00 685
原创 【力扣刷题】【1-50】9. 回文数
9. 回文数1.字符串反转比较可以直接将int转换为string,再将string反转后进行比较;转换成string可以使用to_string函数,to_string(int x);反转使用reverse函数,reverse的使用方式是reverse( s.begin(), s.end() );这种做法简单直接,主要是记录两个函数的用法。博主第一次做力扣周赛时,对代码都还很不熟悉,很简单的反转字符串,reverse函数没有正确使用,卡了很久。class Solution {pu
2022-03-10 23:40:13 70
原创 【力扣刷题】【1-50】8. 字符串转换整数 (atoi)
8. 字符串转换整数 (atoi)1.模拟本体根据题目要求模拟即可,分为以下三个步骤按次处理,如果你的代码有问题,可能是在第二步确定符号,或者是计算过程中没有实时更新结果符号导致的:去除先导的空格,碰到非空格就停止;确定结果的符号,注意这里的符号在第一位就会明确,而没有去除先导零这样的要求,比如说有这样一个样例:00000-42,正确结果是返回0;计算结果的数字部分,遇到其他符号就停止;越界可以根据7. 整数反转 来判断。注意这里或缺的每一位的数字now_val是绝对值而不是真实值,
2022-03-10 23:14:35 73
原创 【力扣刷题】【1-50】7. 整数反转
7. 整数反转1.模拟+数学分析对于取反操作,只需要不断进行(a=x%10;result=result*10+a;)将末尾数字取出后加在结果上即可;这道题的问题在于如何判断超出int的上下界,前置知识:int的表示范围为**[-2147483648,2147483647]**,是32位整数;以0开头的数字有231个,其中有231-1个正数(1-2147483647),全0表示0;以1开头的数字有231个,其中有231个负数,只有第一位是1,其他全0表示-2147483648;
2022-03-10 20:51:42 107
原创 【力扣刷题】【1-50】6. Z 字形变换
6. Z 字形变换1.模拟遍历模拟题目中给出的Z字转换规则,直接得出结果;事先计算清楚结果有几行几列,方便直接使用下标遍历:行数:即是题目中给出的numRows;列数:可以将Z字转换分成一个个操作相同的周期。这里注意,如果将一个完整的“Z”视为一个周期,分析起来比较麻烦,真正的周期是“Z”少了下面一个横的形状。不难看出,每个周期内的元素C=numRows(直线部分)+numRows-2(斜线部分);因此周期数T=s.size()/周期内元素个数C;每个周期有numRows-1列;因
2022-03-09 22:28:17 168
原创 【力扣刷题】【1-50】4. 寻找两个正序数组的中位数
4. 寻找两个正序数组的中位数1.两指针寻找中间位置维护两个指针,哪个链表数字小或者是另一链表走到头,则这一侧的指针后移;如果走到了中位数的位置,就可以返回结果;时间复杂度仍然是O(m+n);class Solution {public: double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m=nums1.size(),n
2022-03-08 16:39:06 482
原创 【力扣刷题】【1-50】2. 两数相加
2. 两数相加1.链表模拟+哑巴节点因为题目给出的链表顺序就是逆序的,符合加法规则,只需要按序取出元素相加即可;在一个链表走到结尾时,若另一链表尚未结束,则补0继续运算;使用哑巴节点,dummy节点,既能避免头节点为空的问题,也便于返回链表结果class Solution {public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode* result=new ListNode();
2022-03-08 15:18:07 201
原创 【力扣刷题】【1-50】3. 无重复字符的最长子串
3. 无重复字符的最长子串本题直接强行遍历可以完成,但是时间复杂度较高,以下代码使用滑动窗口法完成;滑动窗口右指针不需要回溯的原因分析:右指针滑动到C时,因为RT+1元素已经出现,右指针停止滑动此时窗口内的[LT,RT]元素没有重复左指针右移一位,此时左右指针之间的元素仍无重复,右指针在原有位置上继续右移即可unordered_set.count() 如果元素存在于容器中,则此函数返回1,否则返回0。//直接模拟遍历是可以完成的,但是使用滑动窗口时间性能更优秀clas
2022-03-08 11:32:45 68
原创 【力扣刷题】【1-50】 1. 两数之和
1. 两数之和强行遍历法本题直接强行遍历可以完成,但是时间复杂度较高O(n2),以下代码为强行遍历:注意j的起始位置,如果从0开始会产生重复运算,只需要从i+1开始即可。class Solution {public: vector<int> twoSum(vector<int>& nums, int target) { vector<int>result; int n=nums.size();
2022-03-08 11:31:22 478
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人