算法面试8---贪心算法

别来无恙 提交于 2019-11-30 06:13:57

1 简单贪心

贪心算法相对来说代码少,思路简单,但贪心问题的关键是确定一个问题能否使用贪心算法去解决。

例1: LeetCode 455。题解:把最大的饼干分给最贪心的还在,那么剩下的饼干中就是次大的分给次贪心的孩子即还是当前最大的饼干分给最贪心的孩子。在贪心算法中,常常要涉及到最大,最小这些数据因此常常需要进行排序。

class Solution {
    
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int i = 0,j = 0;
        int l1 = g.length,l2= s.length;
        while (i<l1 && j<l2) {
            if (g[i] <= s[j]) {
                i++; //孩子的需求被满足了,可以转到下一个孩子了
            }
            j++; //否则寻找更大的饼干
        }
        return i; //因为i是从0开始的所以直接返回便是满足孩子需求的数目
    }
}

与此类似题目:LeetCode 392。

2 贪心与动态规划的关系

例1:LeetCode 435。题目中是最少需要移除多少区间使得区间不重叠那么也可以理解为最多保留多少个区间使得区间不重叠。暴力思路就是找出所有的子区间然后判断是否重叠,为了判断重叠时方便可以先进行排序,对于组合问题大都可以用动态规划进行优化解决。如果从动态规划去理解,给定一个拍好序的区间,保留最多的区间使得区间不重叠,那么就很类似与最长上升子序列问题。

class Interval{
     int start;
     int end;
    Interval(){
        this.start = 0;
        this.end = 0;
    }
    Interval(int s,int e){
        this.start = s;
        this.end = e;
    }
}

class IntervalsComparator implements Comparator<Interval> {
    @Override
    public int compare(Interval o1, Interval o2) {
        if (o1.start != o2.start) {
            // -1:不交换位置,1:交换位置,从小到大排序
            return o1.start < o2.start ? -1 : 1;
        }
        return o1.end < o2.end ? -1 : 1;
    }
}

public class Solution {

    public int eraseOverlapIntervals(Interval[] intervals) {
        if (intervals == null || intervals.length == 0){
            return 0;
        }
        Arrays.sort(intervals, new IntervalsComparator());
        // memo[i] 表示使用intervals[0...i]的区间能构成的最长不重叠区间序列
        int[] memo = new int[intervals.length];
        // 设定初始值
        Arrays.fill(memo, 1);
        for (int i = 1; i < intervals.length; i++){
            // 求memo[i] 动态转移方程
            for (int j = 0; j < i; j++){
                if (intervals[i].start >= intervals[j].end){
                    memo[i] = Math.max(memo[i], 1 + memo[j]);
                }
            }
        }
        // 在所有的memo中取最大值
        int res = 0;
        for (int i = 0; i < intervals.length; i++){
            res = Math.max(res, memo[i]);
        }
        // 返回需要删除的区间数
        return intervals.length - res;
    }
}

可以注意到:每次选择中,每个区间的结尾很重要,结尾越小,留给后面越大的空间,后面越有可能容纳更多区间。那么贪心算法便可以采用如下思路:按照区间的结尾排序,每次选择结尾最早的,且和前一个区间不重叠的区间。

public class Solution {

    public int eraseOverlapIntervals(Interval[] intervals) {
        if (intervals == null || intervals.length == 0){
            return 0;
        }
        Arrays.sort(intervals, new IntervalsComparator());
        int res = 1;
        int pre = 0;
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i].start >= intervals[pre].end) {
                // 决定选择当前i
                res++;
                // 存储当i
                pre = i;
            }
        }
        return intervals.length - res;
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

0

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!