代码随想录算法训练营 | 贪心算法 part03

134. 加油站

134. 加油站
在这里插入图片描述
剩余油量rest小于0,不能到达下一个加油站;更新下一个加油站为起始加油站;路过加油站数量为gas.size()时,说明可以绕环路行驶一周,返回起始加油站的下标

class Solution {
public:
    int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int count = 0; // 路过加油站的个数
        int sum = 0; // 统计剩余油量
        int len = gas.size();
        // 起点不确定,两倍长度判断是否可以绕一圈
        for (int i = 0; i < 2 * len; ++i) {
            sum += gas[i%len] - cost[i%len];
            count++;
            if (sum < 0) { //剩余油量小于0,无法到达下一个加油站
                sum = 0;
                count = 0;
            }
            if (count == len) {
                return (i + 1) % len;
            }
        }
        return -1;
    }
};

135. 分发糖果

135. 分发糖果

class Solution {
public:
    int candy(vector<int>& ratings) {
        vector<int> candyVec(ratings.size(), 1);
        // 从前向后遍历,比较右边孩子评分比左边大的情况。
        for (int i = 1; i < ratings.size(); i++) {
            if (ratings[i] > ratings[i - 1]){
                candyVec[i] = candyVec[i - 1] + 1;
            }
        }
        // 从后向前遍历,比较左边孩子评分比右边大的情况
        for (int i = ratings.size() - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1] ) {
                candyVec[i] = max(candyVec[i], candyVec[i + 1] + 1);
            }
        }
        // 统计结果
        int sum = 0;
        for (int i = 0; i < candyVec.size(); i++){
            sum += candyVec[i];
        }
        return sum;
    }
};

失败的思路:考虑给评分极小值的孩子分发一颗糖果,但是两个极小值之间的区间不一定是单调的;

860.柠檬水找零

860.柠檬水找零
顾客付钱有三种情况,如下:
1、支付 5 美元,不用找零,直接收下,增加一张 5 美元;
2、支付 10美元,找零一张 5 美元,增加一张 10 美元;
3、支付 20 美元,优先找零一张 10 美元和 5 美元;如果不够,就找零三张 5 美元;同时增加 20 美元;
可以根据上面的情况直接模拟
对于支付 5 美元和支付 10 美元,找零请况是固定的;
因为10 美元只能给 20 美元找零;5 美元可以给 10 美元和 20 美元找零;对于支付 20 美元,就要优先找零 10 美元;
局部最优:顾客支付 20 美元,优先找零一张 10 美元和 5 美元;如果不够,就找零三张 5 美元
全局最优:完成全部账单的找零

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0; // 零钱币值为 5 美元和 10 美元的个数
        for (int i = 0; i < bills.size(); i++) {
            if (bills[i] == 5) { // 顾客付 5 美元, 不用找零
                five++;
            }
            else if (bills[i] == 10) {
                // 顾客付 10 美元, 找零一张 5 美元
                if (five >= 1) { 
                    five--;
                    ten++;
                }else {
                    return false;
                }
            } else if (bills[i] == 20) { 
                if (ten >= 1 && five >= 1) { 
                    // 顾客付 20 美元, 找零一张 10 美元和 5 美元
                    ten--;
                    five--;
                } else if (five >= 3) { 
                    // 顾客付 20 美元, 找零三张 5 美元
                    five -= 3;
                } else {
                    return false;
                }
            }
        }
        return true;
    }
};

406.根据身高重建队列

406.根据身高重建队列
局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性
全局最优:最后都做完插入操作,整个队列满足题目队列属性
按照身高由大到小排序后:
在这里插入图片描述
依次将每个人放入队列中,那么当我们放入第 i 个人时:
0,⋯,i−1 个人已经在队列中被安排了位置,他们只要站在第 i 个人的前面,就会对第 i 个人产生影响,因为他们都比第 i 个人高;
而第 i+1,⋯,n−1 个人还没有被放入队列中,并且他们无论站在哪里,对第 i 个人都没有任何影响,因为他们都比第 i 个人矮。
采用「插空」的方法,依次给每一个人在当前的队列中选择一个插入的位置。也就是说,当我们放入第 i 个人时,只需要将其插入队列中,使得他的前面恰好有 k 个人即可。

class Solution {
public:
    static bool cmp(vector<int>& a, vector<int>& b) {
        if (a[0] == b[0]){ // 身高相等,属性小的在前
            return a[1] < b[1];
        }
        return a[0] > b[0]; // 身高不等,身高大的在前
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        // 身高从大到小排序
        sort (people.begin(), people.end(), cmp);
        vector<vector<int>> res;
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1];
            res.insert(res.begin() + position, people[i]);
        }
        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值