Leetcode分类——贪心算法

一、贪心法

遵循某种规律,不断贪心地选取最优策略来求解。

二、贪心的前提

最优解能够划分成多个次优解,例如找零钱问题中,零钱的种类必须是倍数包含关系(如100,20,10,15,1元),如果包含了50元或7元类型,贪心法求解可能出错,此时应该使用动态规划来做。

三、算法举例

Leetcode 455

题目

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。对每个孩子 i ,都有一个胃口值 gi ,这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j ,都有一个尺寸 sj 。如果 sj >= gi ,我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

注意:
你可以假设胃口值为正。
一个小朋友最多只能拥有一块饼干。

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

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

贪心规律

  1. 如果某个饼干不能满足该孩子,一定不能满足需求因子更大的孩子;
  2. 如果能用更小的饼干满足该孩子,则没必要用更大的;
  3. 需求因子小的孩子更容易被满足,故应从小到大开始分配。

算法思路

  1. 对饼干大小和孩子的需求因子从小到大排序;
  2. 二路遍历,满足条件即比较下一个,直至一路完毕。
class Solution {
    public int findContentChildren(int[] g, int[] s) {
    	//步骤1:排序
        Arrays.sort(g);
        Arrays.sort(s);
        int count = 0, childIndex = 0, cookieIndex = 0;
       	//步骤2:遍历比较
        while (childIndex < g.length && cookieIndex < s.length) {
            if (g[childIndex] <= s[cookieIndex]) {
            	//只有匹配成功,才开始比较下一个(需求因子更大的),计数器也要加1
                ++count;
                ++childIndex;
            }
            //无论成功失败,饼干序列都要加1
            ++cookieIndex;
        }
        return count;
    }
}

Leetcode 402

题目,贪心算法经常和堆栈等数据结构一起出现

给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小。

注意:
num 的长度小于 10002 且 ≥ k。
num 不会包含任何前导零。
示例 1 :

输入: num = "1432219", k = 3
输出: "1219"
解释: 移除掉三个数字 4, 3,2 形成一个新的最小的数字 1219。
示例 2 :

输入: num = "10200", k = 1
输出: "200"
解释: 移掉首位的 1 剩下的数字为 200. 注意输出不能有任何前导零。
示例 3 :

输入: num = "10", k = 2
输出: "0"
解释: 从原数字移除所有的数字,剩余为空就是0

贪心规律

  • 从高位向地位遍历,如果对应的数字大于下一位数字,则把该位去掉。

算法思路

  • 最暴力的解法,删除k个数字即从最高位开始遍历k次;
  • 如何简化:利用栈存储,依次压栈,如果当先待压入的数字小于栈顶元素,则弹栈。(比较过的位数不用动,已经是最小的了)

特殊情况

  • 如果栈空后k仍大于0怎么办?——
  • 如果存在0怎么办?——
public String removeKdigits1(String num, int k) {
        Stack<Integer> stack = new Stack<>();
        String res = "";
        //遍历整个字符串
        for (int i = 0; i < num.length(); ++i){
            int number = num.charAt(i) - '0';
            //贪心算法删除数字,一个数字可以一直删
            while (!stack.empty() && stack.peek() > number && k > 0) {
                stack.pop();
                --k;
            }
            //首位不为0,或者0不在首位时,入栈
            if (number != 0 || !stack.empty())
                stack.push(number);
        }

        //k还有剩余的情况
        while (!stack.empty() && k > 0) {
            stack.pop();
            --k;
        }
        
        //将栈内数字输出到字符串
        while (!stack.empty()){
            res = stack.pop() + res;
        }
        return (res == "")? "0" : res;
    }

其他题目

Leetcode 376

贪心规律:当序列有一段连续的递增或递减时,为形成摇摆子序列,我们只需要保留这段连续的递增或递减的首尾元素,这样更可能使得尾部的后一个元素成为摇摆子序列的下一个元素。
在这里插入图片描述

Leetcode 55

Leetcode 452

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值