本篇文章的主要内容是LeetCode有关贪心算法的习题练习,主要包含如下题目:
44. Wildcard Matching
45. Jump Game II
55. Jump Game
122. Best Time to Buy and Sell Stock II
134. Gas Station
135. Candy
316. Remove Duplicate Letters
321. Create Maximum Number
330. Patching Array
376. Wiggle Subsequence
392. Is Subsequence
402. Remove K Digits
406. Queue Reconstruction by Height
435. Non-overlapping Intervals
452. Minimum Number of Arrows to Burst Balloons
455. Assign Cookies
502. IPO
44. Wildcard Matching
解题思路
使用动态规划的思路,dp[i][j]表示字符串s的前i个字符与字符串p的前j个字符是否匹配,然后:
如果p[j] == '*'
,则dp[i][j+1] = dp[i][j] || dp[i-1][j]
(‘‘匹配与不匹配);
如果`p[j] != ‘‘, 则只有
p[j] == s[i] || p[j] == ‘?’的时候,
dp[i][j+1] = dp[i-1][j]`;
代码
1 | class Solution |
45. Jump Game II
解题思路
维持一个curJump变量,保存目前为止所能跳转到的最大下标,lastJump表示最近一次最大跳转到达的元素下标,遍历整个数组并更新curJump和lastJump变量,如果lastJump已经到达或者超过数组范围,返回跳转计数。
代码
1 | class Solution |
55. Jump Game
解题思路I
直接使用贪心的算法解决,每遍历一个节点,更新最大Jump的距离maxJump,如果maxJump为0则无法跳到最后节点。
代码
1 | class Solution |
解题思路II
对思路I的算法进行优化,维持一个cover变量,记录能够跳到的最大数组下标,每遍历一个节点,更新cover = max(cover, i + nums[i])
,一旦cover >= len - 1
则肯定能够跳到最后一个节点,直接返回true;
代码
1 | class Solution |
122. Best Time to Buy and Sell Stock II
解题思路
股票的买入和抛售,原则就是最低价买入,然后最高价抛售,价格上升的区间就是获取利润的区间,直接遍历整个数组,将上升趋势的价格差额累加起来就得到最终的最大利润。
代码
1 | class Solution |
134. Gas Station
解题思路
- 如果从A点无法到达B点,那么在A、B两点之间任意一点都无法到达B点,也就是说,如果判断得到从A点无法到达B点,那么A、B两点之间的任何一点都不能作为起始点,因为都到达不了B点。(证明:因为B点无法到达,所以B点的cost > gas; 假设A、B中间一点C,因为从A到B点无法到达,所以总体的cost > gas, A点是可以到达C点的,所以AC段cost < gas,那么CB段必定cost > gas,所以C点无法到达B点)
- 对于全部路程,总体gas大于总体cost才有解,否则无解;
代码
1 | class Solution |
135. Candy
解题思路
确保每个小孩至少一颗糖,初始化每个人一颗,同时观察发现,只有当存在等级差别的时候才需要增加糖的数量,向后向前遍历两遍数组,计算需要增加的糖果数量,最后加和给出结果。
代码
1 | class Solution |
316. Remove Duplicate Letters
解题思路
使用栈结构的性质,对于每一个字符,如果已经在栈中了,就跳过;
如果没有在栈中,如果该字符小于栈顶的字符,并且栈顶字符在后面字符串中还有(计数值大于0),则将栈顶元素出栈,然后继续循环判断新的栈顶元素是否需要出栈,循环判断结束后最后将新字符入栈。
代码
1 | class Solution |
321. Create Maximum Number
解题思路
核心算法是遍历k1
,nums1
取k1
个数字,nums2
取k-k1
个数字,都获得其最大值然后进行合并,最后比较大小返回最大的那一个。
这道题学习了StefanPochmann
大神的代码,真的厉害,各种c++的技巧用得太巧妙了。StefanPochmann
大神对于函数重载以及引用等技巧的使用太赞了!
代码
1 | class Solution |
330. Patching Array
解题思路
miss表示[1,n]中我们无法得到的最小值,也就意味着我们可以得到小于miss的所有数字,取值区间为[1, miss)。如果nums数组中有元素num < miss
,之前我们可以得到范围[1, miss)的数值,现在统一加上num就可以得到[1, miss+num)范围的数值;如果数组中没有小于miss的值,则此时我们需要加入一个新的值来达到要求,这里最好的选择是miss,同时结果计数进行累加计算;StefanPochmann
大神详细题解可以参考这个<链接>!
代码
1 | class Solution |
376. Wiggle Subsequence
解题思路
使用贪心算法解决,遍历整个数组,使用pos表示已遍历数组中符合要求的连续数列长度,且最后的difference是正值,neg就表示最后difference是复制的连续数列长度。如此以来,如果nums[i] > nums[i-1]
,则difference是正值,此时pos = neg + 1
,反之neg = pos + 1
;
代码
1 | class Solution |
392. Is Subsequence
解题思路
这道题按照顺序去比较每一个字符是否相同即可;
代码
1 | class Solution |
402. Remove K Digits
解题思路
利用string的栈结构特性,保证位于高位的数字达到最小即可,最后进行字符串的整理和特例处理。
代码
1 | class Solution |
406. Queue Reconstruction by Height
解题思路I
将people数组元素进行排序,然后按照身高从矮到高的顺序置入结果队列中,通过遍历结果队列更新计数值来决定应该置入的位置。
代码
1 | class Solution |
解题思路II
首先还是对people数组排序,身高高的排在前面,身高一样的,前面人少的排在前面。
简单来说就是按照身高从高到低进行排序,然后高个子先置入结果数组中。这样每一个people数组元素置入的时候,由于比他高的全都已经在结果数组中了,所以此时他的位置也就直接确定了,使用insert执行置入操作即可;
代码
1 | class Solution |
435. Non-overlapping Intervals
解题思路
首先对数组进行排序,按照start从小到大进行排序,如果start相同,按照包含区间从小到大进行排序。
遍历整个数组,如果当前interval的start小于前一个interval的end,即cur.start < pre.end
,则此时必定发生overlapping,结果计数加一,如果cur.end < pre.end
时,cur包含在pre中,此时应该舍弃pre并更新cur为新的pre。
反之,如果一开始就cur.start >= pre.end
的话,区间没有overlapping,更新cur为新的pre,继续遍历即可。
代码
1 | class Solution |
452. Minimum Number of Arrows to Burst Balloons
解题思路
首先对points数组进行排序,维持left和right代表公共区间的左右边界,遍历整个数组,如果气球范围出了公共区间,则此时应该射一箭,反之,则应该继续更新公共区间,如此遍历全部气球数组。
注意这里公共区间边界如果left==right也是可以的;遍历过程中最后一箭是没有射出去的,所以res初始化为1。
代码
1 | class Solution |
455. Assign Cookies
解题思路
对两个数组进行排序,首先用最大的饼干来满足要求最高的孩子,如果无法满足,则换下一个要求小一点的孩子,如果能够满足,则执行--
操作继续进行匹配遍历。
代码
1 | class Solution |
502. IPO
解题思路
使用一个大顶堆结构保存现阶段可以进行的项目,使用vector保存那些不能进行的项目,每次都只执行堆顶的利益最大的项目,执行完毕之后,将已执行的项目pop删除,遍历vector更新可执行的项目,置入到堆中并从vector中删除。
代码
1 | class Solution |