代码随想录算法训练营第三十五天

860.柠檬水找零

        本题可以运用简单逻辑来解决,可以发现顾客只会给收银员20,10,5三种美元,并且收银员需要顺序处理顾客的交易,所以只需要维护20,10,5三个变量的值,通过三个变量的值来确定找零的策略。

        收银员只会遇到三种情况:

  1. 收到5元:不需要找零,直接增加变量5的数量1。
  2. 收到10元:找5元,意味着变量10增加1,变量5减少1。
  3. 收到20元:有两种找钱方案,其一是找一张10元,再找一张5元;其二是找三张5元。

     代码自然而然就能写出来。这里我用了一个长度为3的数组表示,其实直接用变量更直观,nums[0]代表5,nums[1]代表10,nums[2]代表20。

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        int nums[3] = {0};
        for(int i = 0; i < bills.size();i++){
            if(nums[0] < 0){
                return false;
            }
            if(bills[i] == 5){
                nums[0]++;
            }
            if(bills[i] == 10){
                nums[0]--;
                nums[1]++;
            }
            if(bills[i] == 20){
                if(nums[1] <= 0){
                    nums[0] -= 3;
                    nums[2]++;
                }else{
                    nums[0]--;
                    nums[1]--;
                    nums[2]++;
                } 
            }
        }
        if(nums[0] < 0){
           return false;
        }
        return true;
    }
};

406.根据身高重建队列

        这题涉及到先处理一个要素,再处理另一个要素的思想。在本题中,可以先处理身高,因为另一个变量是前面有几个人的身高大于或等于起本身,将数组从大到小排序之后,就可以保证每个人前面的其他人肯定是比自己高的,这样做的好处是,可以根据另一个变量的值来向前插入到数组对应的位置,而不需要考虑前面的人是否比自己高。

        因为数组插入操作的时间复杂度很高,所以本题可以用链表list来优化。

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);
        list<vector<int>> que;
        for(int i = 0; i < people.size();i++){
            int position = people[i][1];
            std::list<vector<int>>::iterator it = que.begin();
            while(position--){
                it++;
            }
            que.insert(it,people[i]);
        }
        return vector<vector<int>>(que.begin(),que.end());
    }
};

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

        做这道题目很容易超时,以下是我一开始做出来的代码,结果是超时的。

class Solution {
public:
    static bool cmp(vector<int> a,vector<int> b){
        return a[0] < b[0];
    }
    int findMinArrowShots(vector<vector<int>>& points) {
        if(points.size() == 0)return 0;
        int result = 1;
        sort(points.begin(),points.end(),cmp);
        for(int i = 0; i < points.size()-1;i++){
            if(points[i][1] < points[i+1][0]){
                result++;
            }else{
                points[i+1][1] = min(points[i][1],points[i+1][1]);
            }
        }
        return result;
    }
};

           以下是正确的能够通过的题解。

class Solution {
private:
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        return a[0] < b[0];
    }
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if (points.size() == 0) return 0;
        sort(points.begin(), points.end(), cmp);

        int result = 1; // points 不为空至少需要一支箭
        for (int i = 1; i < points.size(); i++) {
            if (points[i][0] > points[i - 1][1]) {  // 气球i和气球i-1不挨着,注意这里不是>=
                result++; // 需要一支箭
            }
            else {  // 气球i和气球i-1挨着
                points[i][1] = min(points[i - 1][1], points[i][1]); // 更新重叠气球最小右边界
            }
        }
        return result;
    }
};

        仔细对比一下不难发现,两段代码的答题思路是一样的,先按照第一个元素的值排序,这样的话就不要去判断左边界是否有重叠部分,因为靠后的左边界一定是包含在靠前的左边界之前的,然后再去找重叠区间 ,只要当前气球的右区间大于或等于下一个气球大小的左区间,那么两个气球一定有重合区间,于是需要记录这个重叠区间去跟后面的气球比较,怎么记录这个区间?很简单,只需要找前后两个气球有边界的最小值就是重合区间的右边界,因为是前后的顺序比较,每次只需要把重合区间右边界的值赋给下一个元素的右边界就搞定了。如果找不到重叠区间,射箭次数自然就要加一了。

        那为什么类似的代码,我的超时而另一个却不超时,一开始我的想法是for循环开始位置不一样,导致取数的时候(points[i+1][1])做的加减运算多一次,于是我把for循环改成和正确答案一样,依然超时。

        后来是把cmp函数中两个参数改成const引用类型才顺利通过。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值