贪心习题小总结

不要怪笔者写的简陋,真的没有太多时间和精力来整理了。

要使用贪心算法就要证明,贪心策略可以得到全局最优解,因此它并没有动态规划应用那么广泛,但是一旦证明贪心策略的重要性往往可以用O(n)的复杂度解决问题。

一、分配问题

455. 分发饼干

贪心策略:我们先对饼干和孩子排序,拿最小的饼干去满足胃口最小的孩子。

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        int count = 0;
        Arrays.sort(g);
        Arrays.sort(s);
        int start = 0;
        for(int i = 0; i < g.length; i++) {
            for(int j = start; j < s.length; j++) {
                if(s[j] >= g[i]) {
                    count++;
                    start = j + 1;
                    break;
                }
            }
            if(start >= s.length) break;
        }
        return count;
    }
}

135. 分发糖果

策略:

①先给每一个孩子分发一个糖果存在数组a与b中

②数组a从左向右遍历,只要右边的孩子比左边的孩子分数高就多发一枚糖果。

③数组b从右向左遍历,只要左边孩子比右边孩子分数高就多发一枚糖果。

④ans[i] = max{ a[i], b[i] }

class Solution {
    public int candy(int[] ratings) {
        int[] m1 = new int[ratings.length];
        int[] m2 = new int[ratings.length];
        Arrays.fill(m1,1);
        Arrays.fill(m2,1);
        for(int i = 1; i < ratings.length; i++) {
            if(ratings[i]>ratings[i-1]) m1[i] = m1[i-1] + 1;
        }
        for(int i = ratings.length-2; i >=0; i--) {
            if(ratings[i]>ratings[i+1]) m2[i] = m2[i+1] + 1;
        }
        int ans = 0;
        for(int i = 0; i < ratings.length; i++) {
            ans = ans + Math.max(m1[i],m2[i]);
        }
        return ans;
    }
}

二、区间调度问题

这类问题应该是比较经典的贪心问题

435. 无重叠区间

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if(intervals.length == 0) return 0;//这个位置一定注意空值输入,几乎必有
        int count = 1;
        Arrays.sort(intervals,new Comparator<int[]>() {
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        int x_end = intervals[0][1];
        for(int i = 0; i < intervals.length; i++) {
            if(intervals[i][0] >= x_end) {
                count++;
                x_end = intervals[i][1];
            }
        }
        return intervals.length - count;
    }
}

452. 用最少数量的箭引爆气球

class Solution {
    public int findMinArrowShots(int[][] points) {
        if(points.length == 0) return 0;
        int count = 0;
        Arrays.sort(points,new Comparator<int[]>(){
            public int compare(int[] a, int[] b) {
                return a[1] - b[1];
            }
        });
        int s = points[0][1];
        for(int i = 0; i < points.length; i++) {
            if(points[i][0] <= s && s <= points[i][1] ) {
                continue;
            }
            count++;
            s = points[i][1];
        }
        return ++count;
    }
}

406. 根据身高重建队列

策略:

①先排序,按照身高降序,k值升序排序

②按照k值插入到相应的位置,应为排序过后前面高个子肯定大于等于k,要是不大于等于k测试用例就错了

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people, new Comparator<int[]>() {
            public int compare(int[] o1, int[] o2) {
                if(o1[0] < o2[0]) return 1;
                else if(o1[0] == o2[0]) return o1[1]-o2[1];
                else return -1;
            }
        });
        LinkedList<int[]> list = new LinkedList<>();
        for(int[] i : people) {
            list.add(i[1],i);
        }
        return list.toArray(new int[list.size()][2]);
    }
}

三、跳跃问题

55. 跳跃游戏

策略:从后向前遍历,能够到达终点的就是好位置,相反则为坏位置,我们始终记录最左边的好位置,只要本点能够跳过好位置,本点就是好位置

class Solution {
    public boolean canJump(int[] nums) {
        int lastgoodpos = nums.length-1;
        for(int i = lastgoodpos-1; i >=0; i--) {
            if(i+nums[i] >= lastgoodpos)
                lastgoodpos = i;
        }
        return lastgoodpos == 0;
    }
}

45. 跳跃游戏 II

策略:本跳应该跳到(下一跳可以跳到最远的)那个位置,这样保证用最少的跳跳到最远的距离。

相当于在求第i跳可以跳到的最远距离

class Solution {
    //贪心策略:本次跳跳到(下一次跳能够跳到最远的距离)的位置
    //本次跳3,下一跳则能够跳到更远
    public int jump(int[] nums) {
        int end = 0;//本次跳的最远的距离
        int maxpos = 0;//下次跳可以跳的最远的距离
        int ans = 0;
        for(int i = 0; i < nums.length-1; i++) {
            maxpos = Math.max(maxpos,i+nums[i]);
            if(i == end) {
                ans++;
                end = maxpos;
            }
        }
        return ans;
    }
}

 四、其他问题

 763. 划分字母区间

应该比较简单吧,只要找好字母最后一次出现的位置就好,因为至少是从这里开始划分的

class Solution {
    public List<Integer> partitionLabels(String S) {
        HashMap<Character,Integer> hash = new HashMap<>();
        LinkedList<Integer> ans = new LinkedList<>();
        for(int i = 0; i < S.length(); i++)
            hash.put(S.charAt(i),i);
        int start = 0;
        int end = hash.get(S.charAt(0));
        int max = -1;
        for(int i = 0; i < S.length(); i++) {
            int temp = hash.get(S.charAt(i));
            max = Math.max(max,temp);
            if(i == end) {
                if(max>end)
                    end = max;
                else {
                    ans.add(end-start+1);
                    start = end + 1;
                    max = -1;
                    if(start<S.length()) end = hash.get(S.charAt(start));
                }
            }
        }
        return ans;
    }
}

605. 种花问题

重点应该在边界处理上吧

    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int count = 0;
        for(int i = 0; i < flowerbed.length; i++) {
            int l = i == 0 ? 0 : flowerbed[i-1];
            int r = i == flowerbed.length-1 ? 0 : flowerbed[i+1];
            if(flowerbed[i] == 0 && l == 0 && r == 0) {
                count++;
                flowerbed[i] = 1;
            }
        }
        return count >= n;
    }

感觉代码这种东西敲了和没敲真的不一样,敲了可能就会一点,不敲肯定不会。

posted @ 2019-12-02 13:29  卑微芒果  Views(266)  Comments(0Edit  收藏  举报