leetcode之贪心算法刷题总结3
Posted nuist__NJUPT
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之贪心算法刷题总结3相关的知识,希望对你有一定的参考价值。
leetcode之贪心算法刷题总结3
贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择,就能得到问题的答案。贪心算法需要充分挖掘题目中条件,没有固定的模式,解决有贪心算法需要一定的直觉和经验。
贪心算法不是对所有问题都能得到整体最优解。能使用贪心算法解决的问题具有「贪心选择性质」。「贪心选择性质」严格意义上需要数学证明。能使用贪心算法解决的问题必须具备「无后效性」,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。
1-煎饼排序
题目链接:题目链接戳这里!!!
思路:这题的思路和常规的冒泡排序很像,测试用例不唯一,只要满足题目要求就可以,就是每一轮先将最大值所在位置index,从0到index所有元素进行翻转,接下来将0到i的元素进行翻转,i是最后元素的位置,此时就可以把最大的元素放到最后了,如果当前元素已经在最后位置,则不需要翻转。
class Solution
public List<Integer> pancakeSort(int[] arr)
List<Integer> ans = new ArrayList<>() ;
for(int i=arr.length-1; i>0; i--)
int index = 0 ;
for(int j=1; j<=i; j++)
if(arr[index]<=arr[j])
index = j ;
if(index==i)
continue ;
reverse(arr, index) ;
reverse(arr, i) ;
ans.add(index+1) ;
ans.add(i+1) ;
return ans ;
public void reverse(int [] arr, int end)
int begin = 0 ;
while(begin<end)
int temp = arr[begin] ;
arr[begin] = arr[end] ;
arr[end] = temp ;
begin ++ ;
end -- ;
2-三角形的最大周长
题目链接:题目链接戳这里!!!
思路:这一题如果对所有的数依次判断,复杂度就很高了,所以,我们仔细观察会发现,边按升序排序后,只要存在三角形,则三条边一定是连续着的,否则必然不存在三角形,知道这一点就可以立刻写出答案了。
class Solution
public int largestPerimeter(int[] nums)
Arrays.sort(nums) ;
for(int i=nums.length-1; i>=2; i--)
int a = nums[i] ;
int b = nums[i-1] ;
int c = nums[i-2] ;
if(b+c>a)
return a+b+c ;
return 0 ;
3-坏了的计算器
题目链接:题目链接戳这里!!!
思路:逆向思维,用cnt计数,让target尽可能除以2,如果target是偶数,则直接除以2,同时cnt累加1次,如果target是奇数,则先加1除以2,cnt累加2次。
class Solution
public int brokenCalc(int startValue, int target)
int cnt = 0 ;
while(startValue < target)
if(target%2==0)
target /= 2 ;
cnt ++ ;
else
target = (target+1) / 2 ;
cnt += 2 ;
return cnt + startValue - target;
4-一手顺子
题目链接:题目链接戳这里!!!
思路:如果能进行分组,则n%groupSize必然等于0,否则,肯定不能分组,对hand数组按照升序排序,将每个数字出现的次数存入map中,然后遍历所有的hand中的数字,由于升序排序,每次出现在map中必然是最小的,判断连续groupSize的数是否存在即可。
class Solution
public boolean isNStraightHand(int[] hand, int groupSize)
int n = hand.length ;
if(n % groupSize != 0)
return false ;
Arrays.sort(hand) ;
Map<Integer, Integer> map = new HashMap<>() ;
for(int hands : hand)
map.put(hands,map.getOrDefault(hands,0)+1) ;
for(int hands : hand)
if(!map.containsKey(hands)) //如果当前值不存在了,则直接跳过
continue ;
for(int i=0; i<groupSize; i++)//如果当前值存在,则必然为最小,则连续的groupSize个必须存在才能分组
int num = hands + i ;
if(!map.containsKey(num))
return false ;
map.put(num, map.get(num)-1) ;
if(map.get(num) == 0)
map.remove(num) ;
return true ;
5-划分数组为连续数字的集合
题目链接:题目链接戳这里!!!
这一题和上一题是一样的,哈哈,就是题目名字不一样而已,AC代码如下:
class Solution
public boolean isPossibleDivide(int[] nums, int k)
int n = nums.length ;
if(n % k != 0)
return false ;
Arrays.sort(nums) ;
Map<Integer, Integer> map = new HashMap<>() ;
for(int hands : nums)
map.put(hands, map.getOrDefault(hands,0)+1) ;
for(int hands : nums)
if(!map.containsKey(hands))
continue ;
for(int i=0; i<k; i++)
int num = i + hands ;
if(!map.containsKey(num))
return false ;
map.put(num, map.get(num)-1) ;
if(map.get(num)==0)
map.remove(num) ;
return true ;
6-K次取反后最大化的数组和
题目链接:题目链接戳这里!!!
思路:对数组元素进行升序排序,每次当k大于0,执行操作,如果是负数,直接翻转,如果是正数,则判断是否是第一个数,如果是,则剩下的翻转次数,都翻转第一个即可,如果不是第一个数,则比较当前值和前一个值得最小值,剩余得翻转次数都翻转最小值即可。
class Solution
public int largestSumAfterKNegations(int[] nums, int k)
Arrays.sort(nums) ;
for(int i=0; i<nums.length; i++)
if(k>0)
if(nums[i] < 0)
nums[i] = -nums[i] ;
k -- ;
if(i==nums.length-1)
return (k%2)== 0 ? getSum(nums) : (getSum(nums)-2*nums[nums.length-1]) ;
else
if(i==0)
return (k%2==0) ? getSum(nums) : (getSum(nums)-2*nums[0]) ;
else
int min = Math.min(nums[i],nums[i-1]) ;
return (k%2==0) ? getSum(nums) : (getSum(nums)-2*min) ;
return getSum(nums) ;
public int getSum(int [] nums)
int sum = 0;
for(int num : nums)
sum += num ;
return sum ;
7-救生艇
题目链接:题目链接戳这里!!!
思路:每次尽量让目前体重最小得和体重最大的搭配,如果能搭配,就两个人一个船,否则就体重最大的一个船。
class Solution
public int numRescueBoats(int[] people, int limit)
int n = people.length ;
Arrays.sort(people) ;
int left = 0, right = n-1, ans = 0 ;
while(left<=right)
if(people[left]+people[right]<=limit)
left ++ ;
right -- ;
ans ++ ;
return ans ;
8-优势洗牌
题目链接:题目链接戳这里!!!
思路:每次对比nums2中最大值和nums1中的最大值,如果nums1中的最大值大于nums2中的最大值,则可以用nums1中的最大值,否则用nums1中的最小值。
class Solution
public int[] advantageCount(int[] nums1, int[] nums2)
//每次在数组nums1中寻找大于nums2[i]的最小值,如果没有,则选择nums1中的最小值
int [] ans = new int [nums1.length] ;
Arrays.sort(nums1) ;
PriorityQueue<int[]> queue = new PriorityQueue<>(
(a,b) ->
return b[1] - a[1] ;
) ;
for(int i=0; i<nums2.length; i++)
queue.add(new int[] i,nums2[i]) ;
int left = 0, right = nums1.length-1 ;
while(!queue.isEmpty())
int [] arr = queue.poll() ;
if(nums1[right] > arr[1])
ans[arr[0]] = nums1[right--] ;
else
ans[arr[0]] = nums1[left++] ;
return ans ;
9-视频拼接
题目链接:题目链接戳这里!!!
思路:动态规划
dp[i]表示将区间0~i覆盖所需要的最少区间数量
初始时候设置dp数组中的值为最大,dp[0]=0
遍历区间上的点,如果当前点在子区间中,则得到递推式:
dp[i] = Math.min(dp[i],dp[clip[0]]+1) ;
class Solution
public int videoStitching(int[][] clips, int time)
int [] dp = new int [time+1] ;
//dp[i]表示将区间0~i覆盖所需要的最少区间数量
Arrays.fill(dp,Integer.MAX_VALUE-1) ;
dp[0] = 0 ;
for(int i=1; i<=time; i++)
for(int [] clip : clips)
if(i>clip[0] && i<=clip[1])
dp[i] = Math.min(dp[i],dp[clip[0]]+1) ;
return dp[time] == Integer.MAX_VALUE-1 ? -1 : dp[time] ;
思路2:贪心
class Solution
public int videoStitching(int[][] clips, int time)
//贪心策略
int [] max = new int [time] ;
int pre=0, last=0, ans = 0 ;
for(int [] clip : clips)
if(clip[0]<time)
max[clip[0]] = Math.max(max[clip[0]], clip[1]) ;
for(int i=0; i<time; i++)
last = Math.max(last, max[i]) ;
if(last==i)
return -1 ;
else if (pre==i)
pre = last ;
ans ++ ;
return ans ;
10-分割平衡字符串
题目链接:题目链接戳这里!!!
思路:局部左右,全局最优,统计L和R的个数,每次相等则是一个平衡串,然后再重新开始统计L和R的个数。
class Solution
public int balancedStringSplit(String s)
int left = 0, right = 0, ans = 0 ;
for(int i=0; i<s.length(); i++)
if(s.charAt(i)=='L')
left ++ ;
else if(s.charAt(i)=='R')
right ++ ;
if(left==right)
ans ++ ;
left=right=0 ;
return ans ;
11-最长对数链
题目链接
以上是关于leetcode之贪心算法刷题总结3的主要内容,如果未能解决你的问题,请参考以下文章