代码随想录训练营第三十五天打卡|860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球

860.柠檬水找零

一开始我以为最后找零就行,有11个测试用例没通过。分析了测试用例,原来必须当场找零。这意味着只要第一位顾客不使用5块钱买柠檬水,那么就当场收摊了。对于10块钱找零只能使用5块钱,对于20块钱找零可以使用10块钱和5块钱或3个5块钱的组合。且优先使用10块钱和5块钱的组合找零20元,因为10块钱只能用于找零20元,而5块钱能用于10块钱和20块钱的找零,使用范围更广。(注:没零钱出来摆什么摊,5块钱一杯柠檬水?抢钱呢)

1.自己版,修改了两次才AC。都是针对有问题的测试用例缝缝补补,代码逻辑不是非常清晰,但总体没什么问题。针对20块的找零有10块就优先使用10块,没有就全都使用5块,因为两种找零方法都需要使用5块所以只需要判断5块钱剩余数量就行。(注:如果有10块钱的情况下找零失败了,说明没有5块钱了,那么全部用5块钱找零的方法也会失败,所以返回false是没问题的)

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0, twenty = 0;
        for (int i = 0; i < bills.size(); i++) {
            if (bills[i] == 5)
                five++;
            else if (bills[i] == 10) {
                ten++;
                five--;
                if (five < 0)
                    return false;
            } else {
                twenty++;
                if (ten > 0) {//优先使用10块找零
                    ten--;
                    five--;
                } else//没有10块就用5块找零
                    five -= 3;
                if (five < 0)
                    return false;
            }
        }
        return true;
    }
};

2.随想录版,逻辑清晰一点

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int five = 0, ten = 0, twenty = 0;
        for (int bill : bills) {
            // 情况一
            if (bill == 5)
                five++;
            // 情况二
            if (bill == 10) {
                if (five <= 0)
                    return false;
                ten++;
                five--;
            }
            // 情况三
            if (bill == 20) {
                // 优先消耗10美元,因为5美元的找零用处更大,能多留着就多留着
                if (five > 0 && ten > 0) {
                    five--;
                    ten--;
                    twenty++; // 其实这行代码可以删了,因为记录20已经没有意义了,不会用20来找零
                } else if (five >= 3) {
                    five -= 3;
                    twenty++; // 同理,这行代码也可以删了
                } else
                    return false;
            }
        }
        return true;
    }
};

406.根据身高重建队列

1.按照身高排序之后,优先按身高高的people的k来插入,后序插入节点也不会影响前面已经插入的节点。身高相等的情况下按k升序排列,因为如果身高相等先插入k大的节点,那么后序插入身高相等k小的节点可能会影响之前已经插入的身高相等k大的节点。(vector版)

class Solution {
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        if (a[0] == b[0])
        return a[1] < b[1];
        return a[0] > b[0];
    }

public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort(people.begin(), people.end(), cmp);
        vector<vector<int>> result;
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1];
            result.insert(result.begin() + position, people[i]);
        }
        return result;
    }
};

2.list版,效率更高一点。(注:position不能直接用,需要先转换为对应的迭代器类型)

class Solution {
public:
    // 身高从大到小排(身高相同k小的站前面)
    static bool cmp(const vector<int>& a, const 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);
        list<vector<int>> que; // list底层是链表实现,插入效率比vector高的多
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1]; // 插入到下标为position的位置
            std::list<vector<int>>::iterator it = que.begin();
            while (position--) { // 寻找在插入位置
                it++;            //将position转换成迭代器类型
            }
            que.insert(it, people[i]);
        }
        return vector<vector<int>>(que.begin(), que.end());
    }
};

452. 用最少数量的箭引爆气球

1.第一次接触这种题,感觉还是挺抽象的。代码随想录给出的贪心解释是:只射重叠最多的气球,用的弓箭一定最少。我个人觉得这种说法并不容易理解,我认为让每一支箭尽可能射更多的气球这种贪心解释更形象一点。新气球原来的箭能射到,那就不用加箭,只需要调整箭的位置就行。如果射不到那就加一支箭,每次都以重叠部分最小右边界判断新气球能不能射到。

class Solution {
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        return a[0] < b[0]; //排序比较函数,从小到大
    }

public:
    int findMinArrowShots(vector<vector<int>>& points) {
        int arrow = 1; //数组大小>=1,至少需要一支箭
        sort(points.begin(), points.end());       //排序
        for (int i = 1; i < points.size(); i++) { //遍历数组从第二个开始
            if (points[i][0] > points[i - 1][1]) { //=也算重叠
                arrow++;                           //不重叠多用一支箭
            } else { //重叠,更新重叠部分最小右边界
                points[i][1] = min(points[i][1], points[i - 1][1]);
            }
        }
        return arrow;
    }
};

今日总结:公园综合活动。

  • 10
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值