LeetCode贪心题目合集

16 篇文章 0 订阅
12 篇文章 0 订阅

860.Lemonade Change
思路:每次判断收到的钱是5,10,还是20;用five和ten记录拥有的5元和10元个数,如果是5,那么直接five++,如果是10,那么ten++,five–(判断有没有5),如果20,判断有没有10,两种情况。

 bool lemonadeChange(vector<int>& bills) {
        int five = 0,ten = 0;
        for (int bill : bills) {
            if (bill == 5)
                five++;
            else if (bill == 10) {
                if (five < 1)
                    return false;
                five --;
                ten++;
            }
            else if (bill == 20) {
                if (ten) {
                    if (five < 1)
                        return false;
                    ten--;
                    five--;
                }
                else {
                    if (five < 3)
                        return false;
                    five = five - 3;
                }
            }
        }
        return true;
    }

455.Assign Cookies
思路:首先进行排序,让胃口小的和cookie小的在前面。然后从g中遍历,从胃口小的开始满足,如果满足则下一个child,如果不满足,那么下一个cookie,看是否满足。

int findContentChildren(vector<int>& g, vector<int>& s) {
        int res = 0;
        sort(g.begin(),g.end());
        sort(s.begin(),s.end());
        int i = 0, j = 0;
        while (i < g.size() and j < s.size()) {
            if (s[j] >= g[i]) {
                res++;
                i++;
                j++;
            }
            else {
                j++;
            }
        }
        return res;
    }

406.Queue Reconstruction by Height
思路:首先,进行排序,排序规则是,按照身高从大到小排序,如果相等,就按照排序从小到大排序(见sort函数),然后新建一个res数组,遍历排序后的数组,根据排序数字插入。

vector<pair<int, int>> reconstructQueue(vector<pair<int, int>>& people) {
        vector<pair<int,int>> res;
        sort(people.begin(),people.end(),[](pair<int,int> a,pair<int,int> b) {
            return a.first > b.first || (a.first == b.first && a.second < b.second);
        });
        for (auto a : people) {
            res.insert(res.begin() + a.second,a);
        }
        return res;            
    }

621.Task Scheduler
思路:
错误代码:主要是认为空挡部分可以放下剩下的字符,但是可能会出现这种情况,4A3B3C3D,n=2,则使用原来的思路(先放最多类的,再按照类别从前往后填空) 不能获得最小值。所以没有做出来。

int leastInterval(vector<char>& tasks, int n) {
            int res = 0;
            int len = tasks.size();
            vector<int> cnt(26,0);
            for (char c : tasks)
                cnt[c - 'A']++;
            sort(cnt.begin(),cnt.end());
            int max_char = cnt[25];
            int count = 0;
            int i = 25;
            while (i >=0 && cnt[i] == max_char){
                i--;
                count++;
            }
            if (count >= n+1) {
                res = tasks.size();
            }
            else {//这里默认在空格地方,可以放下所有其他字符
                res = (max_char - 1) * (n + 1) + count;
            }
            // res = max(len,(max_char - 1) * (n + 1) + count);
            return res;
        }

正确代码:

int leastInterval(vector<char>& tasks, int n) {
        int res = 0;
        int len = tasks.size();
        vector<int> cnt(26,0);
        for (char c : tasks)
            cnt[c - 'A']++;
        sort(cnt.begin(),cnt.end());
        int max_char = cnt[25];
        int count = 0;
        int i = 25;
        while (i >=0 && cnt[i] == max_char){
            i--;
            count++;
        }
      
        res = max(len,(max_char - 1) * (n + 1) + count);
        return res;
    }

738.Monotone Increasing Digits 单调递增数字
思路:首先把数字转化为字符串,然后对字符串进行操作。观察规律可以知道,从后往前比较,当i-1个数比第i个数大的话,也就是说前边一个数字比后边的数大,那么就让i-1个数减1,后边的数变成最大数字9,我们只需要遍历一遍,记录从后向前数,最后一个需要减1的位置,也就是j,那么把j 之后的数都变成9。

int monotoneIncreasingDigits(int N) {
        string str_N = to_string(N);
        int n = str_N.size();
        int j = n;
        for (int i = n - 1;i > 0; i--) {
            if (str_N[i] >= str_N[i-1])
                continue;
            str_N[i-1] = str_N[i-1] - 1;
            j = i;
        }
        for (int i = j; i < n; i++) {
            str_N[i] = '9';
        }
        return stoi(str_N);
    }

435.Non-overlapping Intervals.非重叠数字
思路:首先对数字对进行排序,然后遍历,如果i个数字对的end大于i+1个数字对的start,说明有重叠,res++,那么就让下一个数字对的end设置为这两个重复数字对中end小的那个,然后继续比对。

int eraseOverlapIntervals(vector<Interval>& intervals) {
        int n = intervals.size();
        int res = 0;
        int last;
        sort(intervals.begin(),intervals.end(),[](Interval& a,Interval& b){
            return a.start < b.start;
        });
        for (int i = 0; i < n-1; i++) {
            if (intervals[i].end > intervals[i+1].start) {//说明有重叠
                res++;
                intervals[i+1].end = min(intervals[i].end,intervals[i+1].end);
            }
            
        }
        return res;
    }

870.Advantage Shuffle
思路:这是个田忌赛马的问题。 B 数组中的每个数字找到与之对应 A 数组中大于它的最小值,如果没有则将其设为 A 数组中没处理数据的最小值。其中用到了C++中map.upper_bound函数(第一次见),所以感觉有点复杂。

vector<int> advantageCount(vector<int>& A, vector<int>& B) {
        vector<int> res;
        map<int,int> m;
        map<int,int>::iterator iter;
        int curNum;
        for (auto a : A) 
            m[a]++;
        for (auto b : B) {
            iter = m.upper_bound(b);
            if (iter != m.end()) {
                curNum = iter->first;
            }
            else {
                curNum = m.begin()->first;
            }
            res.push_back(curNum);
            m[curNum]--;
            if (m[curNum] == 0)
                m.erase(curNum);
        }
        return res;
    }

881.Boats to Save People
思路:先按照体重进行排序,然后每次选取第一个和最后一个进行组合,如果小于limit,说明可以同时拉两个人,i++,j–,res++,如果大于limit,那么只拉重的那个人,i不变,j–,res++;但是这个方法时间太慢。

int numRescueBoats(vector<int>& people, int limit) {
        int res = 0;
        sort(people.begin(),people.end());
        int n = people.size();
        int i = 0,j = n-1;
        while (i <= j) {
            if (people[i] + people[j] <= limit) {
                i++;
                j--;
            }
            else {
                j--;
            }
            res++;
        }
        return res;
    }

767.Reorganize String
思路:这道题的目的是字符串中不能有相同的字符相邻,那么如果最多的那个字符的个数超过了字符串长度的一半,那么一定会相邻,这时候返回“”,反之,一定可以实现这个目标。
统计每个字符的个数,并没有用map,而是用的vector,数量*100,然后+字母序号,最后的vector的值%100,结果就是字符,/100就是字符个数,这里相当秀,用vector同时表示了个数和字符。然后对vector进行排序,从数量最多的字符开始放,而且是隔位放,这样可以保证相同字符一定不相邻。因为原字符串S已经没有用,我们可以在S上进行原址赋值操作。

string reorganizeString(string S) {
        int n = S.size();
        int j = 0;
        vector<int> char_num(26,0);
        for (auto c : S) {
            char_num[c - 'a'] += 100;
        }
        for (int i = 0; i < 26; i++) {
            char_num[i] += i;
        }
        sort(char_num.begin(),char_num.end());
        for (int i = 25; i >= 0; i--) {
            char c = char_num[i] % 100 + 'a';
            int num = char_num[i] / 100;
            if (num > (n+1)/2)
                return "";
            for (int k = 0; k < num; k++) {
                S[j] = c;
                j += 2;
                if (j >= n)
                    j = 1;
            }
        }
        return S;
    }

659.Split Array into Consecutive Subsequences
思路:参考思路

bool isPossible(vector<int>& nums) {
        unordered_map<int,int> cnt,tails;
        for (int num : nums) 
            cnt[num]++;
        for (int num : nums) {
            if (cnt[num] <= 0)
                continue;
            else if (tails[num-1] > 0) {//说明num可以连接上前面的连续数组
                tails[num-1]--;
                tails[num]++;
                
            }
            else if (cnt[num+1] > 0 && cnt[num+2] > 0) {//重新一个新连续数组
                tails[num+2]++;
                cnt[num+1]--;
                cnt[num+2]--;
            }
            else {
                return false;
            }
            cnt[num]--;
        }
        return true;
    }

134.Gas Station
思路:last表示上一个剩余的gas,然后从start开始计算一个环的路程,计算此gas[(start + j) % n] + last - cost[(start + j) % n] < 0,说明走不下去,那么从下一个站点开始算。最后结束如果j的值等于n,说明可以走完环。

int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int n = gas.size();
        for (int i = 0; i < n; i++) {
            int last = 0;
            int start = i;
            int j = 0;
            for (j = 0; j < n; j++) {
                if (gas[(start + j) % n] + last - cost[(start + j) % n] < 0) {
                	
                    break;
                }
                last += gas[(start + j) % n] - cost[(start + j) % n];
            }
            if (j == n)
                return start;
        }
        return -1;
    }

思路2:此方法和上一个思路相同,但是多加了一个处理步骤。也就是i = start + j;当start = i的时候,不可能走完全程,那么说明从start到start+j这一段上的所以点都不可以当做起点,那么我们下一次起始点就不用i+1啦,而是变成start+j+1.所以设置为start+j,加上循环的i++。

int canCompleteCircuit(vector<int>& gas, vector<int>& cost) {
        int n = gas.size();
        for (int i = 0; i < n; i++) {
            int last = 0;
            int start = i;
            int j = 0;
            for (j = 0; j < n; j++) {
                if (gas[(start + j) % n] + last - cost[(start + j) % n] < 0) {
                	i = start + j;
                    break;
                }
                last += gas[(start + j) % n] - cost[(start + j) % n];
            }
            if (j == n)
                return start;
        }
        return -1;
    }

55.Jump Game
思路:计算每一个位置可以到达的最远的位置。如果大于等于最后一个位置,退出循环;如果当i大于reach的时候,说明前边的步骤到不了i位置,也退出循环。最后看reach的值是不是大于等于最后位置。

bool canJump(vector<int>& nums) {
        int n = nums.size();
        int reach = 0;
        for (int i = 0; i < n; i++) {
            if (reach >= (n-1) || i > reach) break;
            reach = max(reach,i + nums[i]);
        }
        return reach >= (n-1);
    }
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值