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

LeetCode 860 柠檬水找零

题目链接:https://leetcode.cn/problems/lemonade-change/

思路:

三种情况:

情况一:给5美元,直接收下

情况二:给10美元,找回5美元

情况三:给20美元:1、给一张十美元和一张五美元;2、给三张五美元

因为五美元适用性更广,所以选择先找回十美元,没有十美元的时候再找五美元。贪心贪在先找回十美元

代码:

  • 使用unordered_map(自写)

class Solution {
public:
    bool lemonadeChange(vector<int>& bills) {
        unordered_map<int,int>change;
        if(bills[0]!=5) return false;
        for(int i = 0;i<bills.size();i++)
        {
            if(bills[i]==5)
                change[bills[i]]++;
            else if(bills[i]==10)
            {
                if(change[5]!=0)
                {
                    change[bills[i]]++;
                    change[5]--;
                }
                else
                    return false;
            }
            else
            {
                if(change[10]!=0&&change[5]!=0)
                {
                    change[bills[i]]++;
                    change[10]--;
                    change[5]--;
                }
                else if(change[10]==0&&change[5]>=3)
                {
                    change[bills[i]]++;
                    change[5] -= 3;
                }
                else 
                    return false;
            }
            // cout<<change[5]<<" "<<change[10]<<" "<<change[20]<<endl;
        }
        return true;
    }
};
  • 直接使用int记录

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;
    }
};

总结

直接模拟题目要求,相对简单。

LeetCode 406 根据身高重建队列

题目链接:https://leetcode.cn/problems/queue-reconstruction-by-height/

思路:

如果题目有多个维度,先尝试确定一个维度,确定下来后再去考虑另外一个维度,不要一起考虑。

如本题,存在身高h和前面比他高的人的数量k,两个维度。

假设先确定k,从小到大排列,会发现最后拍完后k的排列并不符合条件,身高也不符合条件,两个维度哪一个都没确定下来。

所以选择从身高开始排列,身高开始排列也有两种方式,一种从高到低,一种从低到高。最终选择是从高到底排列(身高相同的话,k小的排在前面)

排完后,此时我们可以确定一个维度了,就是身高,前面的节点一定都比本节点高!

所以在按照身高从大到小排序后:

局部最优:优先按身高高的people的k来插入。插入操作过后的people满足队列属性

全局最优:最后都做完插入操作,整个队列满足题目队列属性

插入的过程:

  • 插入[7,0]:[[7,0]]

  • 插入[7,1]:[[7,0],[7,1]]

  • 插入[6,1]:[[7,0],[6,1],[7,1]]

  • 插入[5,0]:[[5,0],[7,0],[6,1],[7,1]]

  • 插入[5,2]:[[5,0],[7,0],[5,2],[6,1],[7,1]]

  • 插入[4,4]:[[5,0],[7,0],[5,2],[6,1],[4,4],[7,1]]

代码:

  • 使用数组

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

    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];
    }

};
  • 使用链表

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        list<vector<int>>queue;
        sort(people.begin(),people.end(),cmp);
        // 使用链表来进行插入
        for(int i = 0;i<people.size();i++)
        {
            int pos = people[i][1];
            std::list<vector<int>>::iterator it = queue.begin();
            while(pos--)
                it++;
            queue.insert(it,people[i]);
        }
        return vector<vector<int>>(queue.begin(),queue.end());
    }

    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];
    }

};

总结

要学会有多个维度时候要如何去解决问题。

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

题目链接:https://leetcode.cn/problems/minimum-number-of-arrows-to-burst-balloons/

思路:

贪心:尽可能的让气球重叠在一起

如何判断气球是否重叠在一起?先对气球数组进行排列,按左边界来排。

模拟射爆气球并不需要真的去移除气球。

如果气球重叠了,那么需要将重叠气球中最小的右边界一直更新给当前气球,如果当下一个气球的左边界大于上一个气球的右边界时,说明二者不重叠,此时,弓箭数量+1。

代码:

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if(points.size()==0)    return 0;
        // 按左边界进行排列
        sort(points.begin(),points.end(),cmp);
        int result = 1; // 记录弓箭数量
        // 从1开始记录重叠的气球
        for(int i = 1;i<points.size();i++)
        {
            // 此时气球的左边界如果大于上一个气球的右边界,说明二者不重叠。前一个气球需要一支弓箭去射爆
            if(points[i][0]>points[i-1][1])
                result++;
            else
            {
                // 将重叠气球的右边界更新为重叠的气球中的最小右边界
                points[i][1] = min(points[i][1],points[i-1][1]);
            }
        }
        return result;
    }

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

总结

思路好理解,代码的具体实现还需要多加努力学习。

今日总结:

加油吧,还有二十五天,时间紧迫。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值