leetcode之贪心算法刷题总结5
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之贪心算法刷题总结5相关的知识,希望对你有一定的参考价值。
leetcode之贪心算法刷题总结5
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择,就能得到问题的答案。贪心算法需要充分挖掘题目中条件,没有固定的模式,解决有贪心算法需要一定的直觉和经验。
贪心算法不是对所有问题都能得到整体最优解。能使用贪心算法解决的问题具有「贪心选择性质」。「贪心选择性质」严格意义上需要数学证明。能使用贪心算法解决的问题必须具备「无后效性」,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
1-使数组唯一的最小增量
题目链接:题目链接戳这里!!!
思路:对数组元素进行升序排序,对于每个元素,如果右侧相邻元素小于等于自己,则右侧相邻元素等于当前元素加1,同时记录增量。
class Solution
public int minIncrementForUnique(int[] nums)
Arrays.sort(nums) ;
int ans = 0 ;
for(int i=0; i<nums.length-1; i++)
if(nums[i+1]<=nums[i])
int temp = nums[i+1] ;
nums[i+1] = nums[i] + 1 ;
ans += nums[i+1] - temp ;
return ans ;
2-移除石子的最大得分
题目链接:题目链接戳这里!!!
思路:实时排序,每次让最大的,第二的分别减少1,直到第二的等于0。
class Solution
public int maximumScore(int a, int b, int c)
int [] nums = new int [] a,b,c ;
Arrays.sort(nums) ;
int ans = 0 ;
//实时排序,每次让最大的,第二的分别减少1,直到第二的等于0
while(nums[1]>0)
nums[2] -- ;
nums[1] -- ;
ans ++ ;
Arrays.sort(nums) ;
return ans ;
思路2:数学法
class Solution
public int maximumScore(int a, int b, int c)
int [] nums = new int [] a,b,c ;
Arrays.sort(nums) ;
if(nums[0]+nums[1]<=nums[2])
return nums[0] + nums[1] ;
return (a+b+c) / 2 ;
3-找出最有竞争力的子序列
题目链接:题目链接戳这里!!!
思路:维护一个单调栈,使得栈中的元素是最有竞争的子序列。保证栈空不出栈,同时保持栈顶元素尽量最小同时要保证栈中有k个数字。
class Solution
public int[] mostCompetitive(int[] nums, int k)
//维护一个单调栈即可
Stack<Integer> stack = new Stack<>() ;
int len = nums.length ;
for(int i=0; i<len; i++)
while(!stack.isEmpty() && stack.peek()>nums[i] && len-i>=k-stack.size()+1)
stack.pop() ;
if(k-stack.size()>0)
stack.push(nums[i]) ;
int [] ans = new int [k] ;
while(k>0)
ans[--k] = stack.pop() ;
return ans ;
4-分割数组为连续子序列
题目链接:题目链接戳这里!!!
思路:用两个hash表做记录,第一个hash表count记录每个元素出现的次数,第二个hash表tail记录以nums[i]结尾的字符串个数。
具体思路可以参考这个链接:具体思路参考链接戳这里!!!
class Solution
public boolean isPossible(int[] nums)
//两个哈希表一个记录每个元素出现的次数,另一个记录以i结尾的子序列个数
Map<Integer, Integer> count = new HashMap<>() ;
Map<Integer, Integer> tail = new HashMap<>() ;
for(int i=0; i<nums.length; i++)
count.put(nums[i], count.getOrDefault(nums[i], 0) + 1) ;
for(int i=0; i<nums.length; i++)
int cnt = count.getOrDefault(nums[i],0) ;
if(cnt<=0)
continue ;
else if(tail.getOrDefault(nums[i]-1, 0) > 0)
count.put(nums[i], count.get(nums[i])-1) ;
tail.put(nums[i]-1,tail.get(nums[i]-1)-1) ;
tail.put(nums[i],tail.getOrDefault(nums[i],0)+1) ;
else if(count.getOrDefault(nums[i]+1, 0)>0 && count.getOrDefault(nums[i]+2, 0) > 0)
count.put(nums[i], count.get(nums[i])-1) ;
count.put(nums[i]+1, count.get(nums[i]+1)-1) ;
count.put(nums[i]+2, count.get(nums[i]+2)-1) ;
tail.put(nums[i]+2, tail.getOrDefault(nums[i]+2,0)+1) ;
else
return false ;
return true ;
5-使绳子变成彩色的最短时间
题目链接:题目链接戳这里!!!
思路:从前向后遍历所有气球的颜色,如果相邻的两个元素相同,则开始考虑删除气球,分为两种情况。
如果左侧的气球用时更少,则直接删除即可。
如果右侧的气球用时更少,除了删除气球,还需要将左侧气球的用时更新到下一个位置。
class Solution
public int minCost(String colors, int[] neededTime)
int ans = 0 ;
for(int i=1; i<colors.length(); i++)
if(colors.charAt(i)==colors.charAt(i-1))
if(neededTime[i]>=neededTime[i-1])
ans += neededTime[i-1] ;
else
ans += neededTime[i] ;
neededTime[i] = neededTime[i-1] ;
return ans ;
6-乘积为正数的最大子数组的长度
题目链接:题目链接戳这里!!!
思路1:贪心策略
positive表示以当前下标i结尾乘积为正的子数组长度,negative表示以当前下标i结尾的乘积为负的子数组长度;对于每个数字,分为大于0,小于0,等于0三种情况讨论。
class Solution
public int getMaxLen(int[] nums)
//positive表示以当前下标i结尾乘积为正的子数组长度,negative表示乘积为负的子数组长度
int positive = (nums[0] > 0 ? 1 : 0) ;
int negative = (nums[0] < 0 ? 1 : 0) ;
int maxLength = positive ;
for(int i=1; i<nums.length; i++)
if(nums[i]>0)
positive ++ ;
negative = (negative > 0 ? negative+1 : negative) ;
else if(nums[i]<0)
int newNegative = positive + 1 ;
int newPositive = (negative>0 ? negative+1 : 0) ;
negative = newNegative ;
positive = newPositive ;
else
positive = negative = 0 ;
maxLength = Math.max(maxLength, positive) ;
return maxLength ;
思路2:动态规划
动态规划,positive[i]表示以i结尾的最长正数子数组长度,negative[i]表示以i结尾的最长负数子数组的长度.
我们很容易得到递推表达式。
class Solution
public int getMaxLen(int[] nums)
//动态规划,positive[i]表示以i结尾的最长正数子数组长度,negative[i]表示以i结尾的最长负数子数组的长度
int [] positive = new int [nums.length] ;
int [] negative = new int [nums.length] ;
if(nums[0]>0)
positive[0] = 1 ;
else if(nums[0] < 0)
negative[0] = 1 ;
int maxLength = positive[0] ;
for(int i=1; i<nums.length; i++)
if(nums[i]>0)
positive[i] = positive[i-1] + 1 ;
negative[i] = (negative[i-1] > 0 ? negative[i-1]+1 : 0) ;
else if(nums[i]<0)
positive[i] = (negative[i-1]>0 ? negative[i-1] + 1 : 0) ;
negative[i] = positive[i-1] + 1 ;
else
positive[i] = negative[i] = 0 ;
maxLength = Math.max(maxLength, positive[i]) ;
return maxLength ;
7-峰与谷
题目链接:题目链接戳这里!!!
思路:从前向后遍历,保证奇数位置的大于偶数位置的,不满足条件就交换两个元素值。
class Solution
public void wiggleSort(int[] nums)
//从前向后遍历,保证奇数位置的大于偶数位置的
for(int i=0; i<nums.length-1; i++)
if(i%2==0)
if(nums[i]<nums[i+1])
swap(nums, i, i+1) ;
else
if(nums[i]>nums[i+1])
swap(nums, i, i+1) ;
public void swap(int [] nums, int i, int j)
int temp = nums[i] ;
nums[i] = nums[j] ;
nums[j] = temp ;
8-不同字符的最小子序列
题目链接:题目链接戳这里!!!
思路:维护一个单调栈,如果栈顶元素在s的后面还有,并且当前字符栈顶元素大于当前s中的元素,则出栈,s中的元素进栈。如果当前元素已经在栈中了,则直接跳过。
class Solution
public String smallestSubsequence(String s)
//就是删除重复的字符,使得不同字符组成的字典序最小的字符串,维护一个单调栈就可以
Stack<Character> stack = new Stack<>() ;
for(int i=0; i<s.length(); i++)
char c = s.charAt(i) ;
if(stack.contains(c))
continue ;
while(!stack.isEmpty() && stack.peek()>c && s.indexOf(stack.peek(),i)!=-1)
stack.pop() ;
stack.push(c) ;
String ans = "" ;
for(int i=0; i<stack.size(); i++)
ans += stack.get(i) ;
return ans ;
9-有效的括号字符串
题目链接:题目链接戳这里!!!
思路:max与min分别表示未匹配的左括号的最大值和最小值
如果遇到左括号,则将最小值和最大值分别加 1;
如果遇到右括号,则将最小值和最大值分别减 1;
如果遇到星号,则将最小值减 1,将最大值加 1。
class Solution
public boolean checkValidString(String s)
//max与min分别表示未匹配的左括号的最大值和最小值
int max = 0, min = 0 ;
for(int i=0; i<s.length(); i++)
if(s.charAt(i) == '(')
max ++ ;
min ++ ;
leetcode之贪心算法刷题总结2