隐藏
Single

贪心(一) 基础

贪心的本质是选择每一阶段的局部最优,从而达到全局最优

例如,有一堆钞票,你可以拿走十张,如果想达到最大的金额,你要怎么拿?

指定每次拿最大的,最终结果就是拿走最大数额的钱。

每次拿最大的就是局部最优,最后拿走最大数额的钱就是推出全局最优

什么时候用贪心?

不知道,感觉能用就用。

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(vector<int>& g, vector<int>& s) {

        sort(g.begin(),g.end());

        sort(s.begin(),s.end());

        int res=0;

        int index=g.size()-1;

        for(int i=s.size()-1;index>=0&&i>=0;i--){//先遍历饼干

            if(g[index]<=s[i]){

                index--;

                res++;

            }

            else{

                index--;

                i++;

            }

        }

        return res;

    }

};

 

class Solution {

public:

    int findContentChildren(vector<int>& g, vector<int>& s) {

        sort(g.begin(), g.end());

        sort(s.begin(), s.end());

        int index = s.size() - 1; // 饼干数组的下标

        int result = 0;

        for (int i = g.size() - 1; i >= 0; i--) { // 遍历胃口

            if (index >= 0 && s[index] >= g[i]) {

                result++;

                index--;

            }

        }

        return result;

    }

};

1005. K 次取反后最大化的数组和

给你一个整数数组 nums 和一个整数 k ,按以下方法修改该数组:

  • 选择某个下标 i 并将 nums[i] 替换为 -nums[i] 。

重复这个过程恰好 k 次。可以多次选择同一个下标 i 。

以这种方式修改数组后,返回数组 可能的最大和 。

 

示例 1:

输入:nums = [4,2,3], k = 1
输出:5
解释:选择下标 1 ,nums 变为 [4,-2,3] 。

示例 2:

输入:nums = [3,-1,0,2], k = 3
输出:6
解释:选择下标 (1, 2, 2) ,nums 变为 [3,1,0,2] 。

思路:

反正不用在乎顺序,谁管你什么下标,一直sort去转最小的那个就行了。

代码如下:

class Solution {

public:

    int largestSumAfterKNegations(vector<int>& nums, int k) {

        sort(nums.begin(), nums.end());

        int sum = 0;

        for (int i = 0; i < k; i++) {

            nums[0] = -nums[0];

            sort(nums.begin(), nums.end());

        }

        for (int x : nums) {

            sum += x;

        }

        return sum;

    }

};

但是这样做的话没有锻炼意义,这道题正经用贪心的思路是用两次贪心。

1.局部最优:让绝对值大的负数变为正数。整体最优:整个数组和达到最大。

2.如果将负数都转变为正数了,K依然大于0。局部最优:只找数值最小的正整数进行反转。全局最优:整个 数组和 达到最大。

代码如下:

class Solution {

    static bool cmp(int a, int b) { return abs(a) > abs(b); }

public:

    int largestSumAfterKNegations(vector<int>& A, int K) {

        sort(A.begin(), A.end(), cmp);

        for (int i = 0; i < A.size(); i++) { // 1贪

            if (A[i] < 0 && K > 0) {

                A[i] *= -1;

                K--;

            }

        }

        if (K % 2 == 1)

            A[A.size() - 1] *= -1; // 2贪

        int result = 0;

        for (int a : A)

            result += a;

        return result;

    }

};

860. 柠檬水找零

在柠檬水摊上,每一杯柠檬水的售价为 5 美元。顾客排队购买你的产品,(按账单 bills 支付的顺序)一次购买一杯。

每位顾客只买一杯柠檬水,然后向你付 5 美元、10 美元或 20 美元。你必须给每个顾客正确找零,也就是说净交易是每位顾客向你支付 5 美元。

注意,一开始你手头没有任何零钱。

给你一个整数数组 bills ,其中 bills[i] 是第 i 位顾客付的账。如果你能给每位顾客正确找零,返回 true ,否则返回 false 。

 

示例 1:

输入:bills = [5,5,5,10,20]
输出:true
解释:
前 3 位顾客那里,我们按顺序收取 3 张 5 美元的钞票。
第 4 位顾客那里,我们收取一张 10 美元的钞票,并返还 5 美元。
第 5 位顾客那里,我们找还一张 10 美元的钞票和一张 5 美元的钞票。
由于所有客户都得到了正确的找零,所以我们输出 true。

示例 2:

输入:bills = [5,5,10,10,20]
输出:false
解释:
前 2 位顾客那里,我们按顺序收取 2 张 5 美元的钞票。
对于接下来的 2 位顾客,我们收取一张 10 美元的钞票,然后返还 5 美元。
对于最后一位顾客,我们无法退回 15 美元,因为我们现在只有两张 10 美元的钞票。
由于不是每位顾客都得到了正确的找零,所以答案是 false。

思路:

有如下三种情况:

  • 情况一:账单是5,直接收下。
  • 情况二:账单是10,消耗一个5,增加一个10
  • 情况三:账单是20,优先消耗一个10和一个5,如果不够,再消耗三个5

贪心体现在情况三,选最大的面值先进行消耗。

其实这道题太放水了,明明可以出的更复杂的。

代码如下:

class Solution {

public:

    bool lemonadeChange(vector<int>& bills) {

        int money_5 = 0;

        int money_10 = 0;

        for (int i = 0; i < bills.size(); i++) {

            if (bills[i] == 5) {

                money_5++;

            } else if (bills[i] == 10) {

                if (money_5 > 0) {

                    money_5--;

                    money_10++;

                } else

                    return false;

            } else {

                if (money_10 > 0 && money_5 > 0) {

                    money_5--;

                    money_10--;

                } else if (money_10 == 0 && money_5 >= 3) {

                    money_5 -= 3;

                } else

                    return false;

            }

        }

        return true;

    }

};

暂无评论

发表评论

HTMLCOPY