leetcode之贪心算法刷题总结2

Posted nuist__NJUPT

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了leetcode之贪心算法刷题总结2相关的知识,希望对你有一定的参考价值。

leetcode之贪心算法刷题总结2

贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择,就能得到问题的答案。贪心算法需要充分挖掘题目中条件,没有固定的模式,解决有贪心算法需要一定的直觉和经验。

贪心算法不是对所有问题都能得到整体最优解。能使用贪心算法解决的问题具有「贪心选择性质」。「贪心选择性质」严格意义上需要数学证明。能使用贪心算法解决的问题必须具备「无后效性」,即某个状态以前的过程不会影响以后的状态,只与当前状态有关。

1-数组拆分I
题目链接:题目链接戳这里!!!

思路: 对数组进行升序排序,在每两个之间选择一个最小的累加即可,基础贪心。

class Solution 
    public int arrayPairSum(int[] nums) 
         Arrays.sort(nums) ;
         int ans = 0 ;
         for(int i=0; i<nums.length-1; i+=2)
             ans += Math.min(nums[i],nums[i+1]) ;
         
         return ans ;
    


2-用最少数量的箭引爆气球
题目链接:题目链接戳这里!!!

思路:这一题算是一个经典的贪心策略的应用了,想使用最少数量的箭引爆所有的气球,我们可以按照气球结束的直径坐标进行排序,然后对所有的气球的起始坐标进行遍历,如果下一次的起始大于当前的大于当前的结束,说明必须增加一只箭才能引爆,同时需要更新当前气球直径的结束坐标。

class Solution 
    public int findMinArrowShots(int[][] points) 
//按照气球直径结束的坐标进行排序,如果下一次开始大于当前的结束,需要增加一只箭,同时更新当前结束位置
    if(points.length==0)
        return 0 ;
    
    int ans = 1 ;
    Arrays.sort(points, new Comparator<int []>()
        public int compare(int [] points1, int [] points2)
            if(points1[1]>points2[1])
                return 1 ;
            else if(points1[1]<points2[1])
                return -1 ;
            else
                return 0 ;
            
        
    ) ;
    int p = points[0][1] ;
    for(int [] point : points)
        if(point[0] > p)
            p = point[1] ;
            ans ++ ;
        
    
    return ans ;
    


3-无重叠区间
题目链接:题目链接戳这里!!!

思路:这一题是上一题的变种题,也是按照区间尾部升序排序,然后如果有区间的开始大于等于尾部,则需要ans++,同时更新区间尾部,最后的ans就是可以保留的最大无重叠区间个数,n-ans则是需要删除的最少区间个数。

class Solution 
    public int eraseOverlapIntervals(int[][] intervals) 
        //用ans去记录可以保留的最多区间数,n-ans就是可以删除的最少区间数
        int n = intervals.length ;
        if(n==0)
            return 0 ;
        
        Arrays.sort(intervals,new Comparator<int[]>()
            public int compare(int [] intervals1, int [] intervals2)
                return intervals1[1] - intervals2[1] ;
            
        ) ;
        
        int ans = 1 ;
        int pos = intervals[0][1] ;
        for(int [] interval : intervals)
            if(interval[0] >= pos)
                ans ++ ; //计算出能保留最大不重叠区间个数
                pos = interval[1] ;
            
        
        return n - ans ;
    


4-最短无序连续子数组
题目链接:题目链接戳这里!!!

思路:对原数组进行升序排序,然后将排序后的数组和原数组进行比较,找出左右不相同的位置,相减就是需要排序的最短无序子数组长度。

class Solution 
    public int findUnsortedSubarray(int[] nums) 
        int n = nums.length ;
        if(n==0)
            return 0 ;
        
        int [] sort = new int [n] ;
        for(int i=0; i<n; i++)
            sort[i] = nums[i] ;
        
        Arrays.sort(sort) ;
        int left = 0, right = n-1 ;
        for(int i=0; i<n; i++)
            if(nums[i]==sort[i])
                left++ ;
            else
                break ;
            
        
        for(int i=n-1; i>=0; i--)
            if(nums[i]==sort[i])
                right -- ;
            else
                break ;
            
        
        return (right - left + 1) > 0 ? right-left+1 : 0 ;
    


5-分发饼干
题目链接:题目链接戳这里!!!

思路:对数组g和数组s进行升序排序,然后双指针判断即可。

class Solution 
    public int findContentChildren(int[] g, int[] s) 
        int n = g.length ;
        int m = s.length ;
        if(m==0)
            return 0 ;
        
        Arrays.sort(g) ;
        Arrays.sort(s) ;
        int a=0, b=0 ;
        int ans = 0 ;
        while(a<n && b<m)
            if(g[a]<=s[b])
                ans ++ ;
                a ++ ; 
                b ++ ;
            else
                b ++ ;
            
        
        return ans ;
    


6-分发糖果
题目链接:题目链接戳这里!!!

思路:这道题在贪心中不太好理解,其实就是分为两个过程,一次从左向右遍历,一次从右向左遍历,从左向右遍历过程中,如果当前孩子的评分大于前一个,则当前孩子的糖果等于前一个孩子的糖果数量加1,否则当前孩子的糖果数等于,从右向左遍历则类似,依次类推,对比对应的左右统一孩子的最大值即为该孩子的糖果数。

class Solution 
    public int candy(int[] ratings) 
        //一次从左向右遍历,一次从右向左遍历
        int n = ratings.length ;
        int [] left = new int [n] ;
        for(int i=0; i<n; i++)
            if(i>0 && ratings[i]>ratings[i-1])
                left[i] = left[i-1]+1 ;
            else
                left[i] = 1  ;
            
        
        int right = 0 ;
        int ans = 0 ;
        for(int i=n-1; i>=0; i--)
            if(i<n-1 && ratings[i] > ratings[i+1])
                right ++ ;
            else
                right = 1 ;
            
            ans += Math.max(left[i],right) ;
        
        return ans ;
    


7-种花问题
题目链接:题目链接戳这里!!!

思路:计数法,每次中间满足连续的三个则ans累加1,如果左边或者右边有两个,也是可以累加1的。

class Solution 
    public boolean canPlaceFlowers(int[] flowerbed, int n) 
        int ans = 0, cnt = 1; //cnt初始化为1,前面两个0也是可以的
        for(int i=0; i<flowerbed.length; i++)
            if(flowerbed[i]==0)
                cnt ++ ;
            else
                cnt = 0 ;
            
            if(cnt == 3)
                ans ++ ;
                cnt = 1 ;
            
        
        if(cnt == 2)
            ans ++ ;
        
        return n <= ans ;
    


8-有效的三角形个数
题目链接:题目链接戳这里!!!

思路:对数组元素进行升序排序,每次固定最长的边,双指针遍历其他边。

class Solution 
    public int triangleNumber(int[] nums) 
        int n = nums.length ;
        if(n<3)
            return 0 ;
        
        int ans = 0 ;
        Arrays.sort(nums) ;
        for(int i=nums.length-1; i>=2; i--)
            int left = 0, right = i-1, k = nums[i] ;
            while(left<right)
                if(nums[left]+nums[right]>k)
                    ans += right - left ;
                    right -- ;
                else
                    left ++ ;
                
            
        
        return ans ;
    

9-划分字母区间
题目链接:题目链接戳这里!!!

思路:用map记录每个字母最后出现的位置,然后从前向后遍历,如果当前位置等于字符串中所有字母的最后出现的那个位置,则截取当前字符串,继续遍历后面的字符串。

class Solution 
    public List<Integer> partitionLabels(String s) 
        Map<Character, Integer> map = new HashMap<>() ;
        for(int i=0; i<s.length(); i++)
            map.put(s.charAt(i),i) ;
        
        List<Integer> ans = new ArrayList<>() ;
        int left = 0, right = 0 ;
        for(int i=0; i<s.length(); i++)
             right = Math.max(right,map.get(s.charAt(i))) ;
            if(i==right)
                ans.add(right-left+1) ;
                left = right + 1 ;
                right = 0 ;
            
        
        return ans ;
    


10-森林中的兔子
题目链接:题目链接戳这里!!!

思路:这题可以很巧妙的不用hashmap,直接用一维数组,效率更高,其实思路还是一样,两只相同颜色的兔子看到的其他同色兔子数必然是相同的。反之,若两只兔子看到的其他同色兔子数不同,那么这两只兔子颜色也不同。
因此,将answers 中值相同的元素分为一组,对于每一组,计算出兔子的最少数量,然后将所有组的计算结果累加,就是最终的答案。

class Solution 
    public int numRabbits(int[] answers) 
        int [] map = new int [1000] ;
        int ans = 0 ;
        //同种颜色的肯定肯定会报的其它颜色也一样
        for(int i=0; i<answers.length; i++)
            if(map[answers[i]]>0) //回答颜色已经出现
                map[answers[i]] -- ;
            else //构建回答的新颜色
                map[answers[i]] = answers[i] ;
                ans += answers[i] + 1 ;
            
        
        return ans ;
    


11-柠檬水找零
题目链接:题目链接戳这里!!!

思路:使用两个变量five和ten模拟商家手上拥有的5和10元的个数,枚举每一种情况,依次判断即可。

class Solution 
    public boolean lemonadeChange(int[] bills) 
        int money = 0, five = 0, ten = 0 ; 
        //模拟商家手头5和10的个数
        for(int bill : bills)
            if(bill==5)
                five ++ ;
            else if(bill==10)
                ten ++ ;
                if(five>=1)
                    five -- ;
                else
                    return false ;
                
            else if(bill == 20)
                if(ten>0 && five>0)
                    ten -- ;
                    five -- ;
                else if(five>=3)
                    five -= 3 ;
                else
                    return false ;
                
            
        
        return true ;
    


12-重构字符串
题目链接:题目链接戳这里!!!

思路:依次记录每个字符出现的次数,如果最大的字符出现次数大于(n+1)/2,则不能重构字符串,否则可以重构字符串,在重构字符串的过程中,如果当前字符出现的次数大于0,且小于等于n/2,则可以放到奇数位,只要字符出现次数大于0就可以放到偶数位。

class Solution 
    public String reorganizeString(String s) 
        int n = s.length() ;
        if(n<2)
            return s ;
        
        int maxCount = 0 ;
        int [] cnt = new int [26] ;
        for(int i=0; i<n; i++)
            cnt[(int)(s.charAt(i)-'a')] ++ ;
            maxCount = Math.max(maxCount, cnt[s.charAt(i)-'a']) ;
        
        if(maxCount>(n+1)/2)
            return "" ;
        
        int oddIndex = 1, evenIndex = 0 ;
        char [] ans = new char [n] ;

        for(int i=0; i<26以上是关于leetcode之贪心算法刷题总结2的主要内容,如果未能解决你的问题,请参考以下文章

leetcode之贪心算法刷题总结4

leetcode之贪心算法刷题总结1

leetcode之贪心算法刷题总结5

Leetcode刷题100天—452. 用最少数量的箭引爆气球(贪心)—day38

Leetcode刷题100天—452. 用最少数量的箭引爆气球(贪心)—day40

leetcode刷题贪心算法-第1篇