编程语言
首页 > 编程语言> > 【LeetCode】贪心算法:常见典例

【LeetCode】贪心算法:常见典例

作者:互联网

贪心算法

如果问题的最优解包含两个(或更多)子问题的最优解,且子问题多有重叠,我们考虑使用动态规划算法。
而如果问题经过贪心选择后,只剩下
一个
子问题,且具有优化子结构,那么可以使用贪心算法。

贪心选择性:每一步贪心选出来的一定是原问题的最优解的一部分(即每次求的最优解一定会被更大的父问题选择,即被父节点选择)

最优子结构:每一步贪心选完后会留下子问题,子问题的最优解和贪心选出来的解可以凑成原问题的最优解

贪心算法的实现框架

定义解元素集合

// 从初始状态出发;
while (能朝给定总目标前进一步){ 
	利用可行的决策,求出可行解的一个解元素并加入解集合;
}

由所有解元素组合成问题的一个可行解;

455. 分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。

示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。
所以你应该输出2.

题解

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);

        int res = 0;
        for(int sIdx = s.length - 1 , gIdx = g.length - 1; sIdx != -1 && gIdx != -1 ; ){
            if(s[sIdx] >= g[gIdx]){
                res ++;
                sIdx --;
                gIdx --;
            }else {
                gIdx --;
            }
        }

        return res;
    }
}

392. 判断子序列

给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,"ace"是"abcde"的一个子序列,而"aec"不是)。

示例 1:

输入:s = "abc", t = "ahbgdc"
输出:true

示例 2:

输入:s = "axc", t = "ahbgdc"
输出:false

题解

class Solution {
    public boolean isSubsequence(String s, String t) {
        int sIdx = 0;
        for(int tIdx = 0 ; tIdx < t.length() ; tIdx ++){
            if(sIdx <= s.length() - 1 && s.charAt(sIdx) == t.charAt(tIdx)){
                sIdx ++;
            }
        }

        return sIdx == s.length();
    }
}

435. 无重叠区间

给定一个区间的集合,找到需要移除区间的最小数量,使剩余区间互不重叠。

注意:

可以认为区间的终点总是大于它的起点。
区间 [1,2] 和 [2,3] 的边界相互“接触”,但没有相互重叠。

示例 1:

输入: [ [1,2], [2,3], [3,4], [1,3] ]

输出: 1

解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

输入: [ [1,2], [1,2], [1,2] ]

输出: 2

解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

输入: [ [1,2], [2,3] ]

输出: 0

解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

动态规划

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals , (o1 , o2) -> (o1[0] != o2[0] ? o1[0] > o2[0] : o1[1] > o2[1]) ? 1 : -1);

        int[] dp = new int[intervals.length + 1];
        for(int i = intervals.length - 1 ; i >= 0 ; i --){
            for(int j = i + 1 ; j < intervals.length ; j ++){
                if(intervals[j][0] >= intervals[i][1]){
                    dp[i] = Math.max(dp[i] , dp[j] + 1);
                }
            }
            dp[i] = dp[i] == 0 ? 1 : dp[i];
        }

        int max = 0;
        for(int i = 0 ; i < dp.length ; i ++){
            max = Math.max(dp[i] , max);
        }

        return intervals.length - max;

    }
}

贪心算法

class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        if (intervals.length == 0) {
            return 0;
        }
        // 注意,这里是根据结尾元素大小排序
        Arrays.sort(intervals,(o1 , o2) -> o1[1] > o2[1] ? 1 : o1[1] < o2[1] ? -1 : o1[0] > o2[0] ? 1 : o1[0] < o2[0] ? -1 : 0);
        int count = 1;	//最多能组成的不重叠区间个数
        int end = intervals[0][1];
        for (int i = 0; i < intervals.length; i++) {
            if (intervals[i][0] < end) {
                continue;
            }
            end = intervals[i][1];
            count++;
        }
        return intervals.length - count;
    }
}

标签:典例,int,length,intervals,o1,LeetCode,dp,贪心
来源: https://blog.csdn.net/weixin_43934607/article/details/113786651