一、贪心算法

本文详细介绍了贪心算法的基本思想,并结合LeetCode题目,包括分配问题、区间问题和练习题,如Assign Cookies、Candy、Non-overlapping intervals等,通过实例解析贪心算法的解题策略和步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、贪心算法

保证每次操作都是局部最优的,从而使最后得到的结果是全局最优的。

1 分配问题

1.1 Assign Cookies(Easy) 455.分发饼干

https://leetcode-cn.com/problems/assign-cookies/

题解:

饥饿度最小的孩子最容易吃饱,所以先考虑这个孩子,把大于等于这个孩子饥饿度的、且大小最小的饼干给这个孩子。所以先对孩子和饼干按照从小到大排序然后循环筛选。

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());

        int child = 0, cookie = 0;
        while (child < g.size() && cookie < s.size()){
            if (g[child] <= s[cookie]) child++;
            cookie++;
        }
        return child;
    }
};

1.2 Candy(hard) 135.分发糖果

https://leetcode-cn.com/problems/candy/

题解:

两次遍历,先从左到右,然后从右到左,判断两边的数值是否比中间的大。

class Solution {
public:
    int candy(vector<int>& ratings) {
        // sort(ratings.begin(), ratings.end());
        int length = ratings.size();
        if (length < 2) return length;
        vector<int> nums(length, 1);
        for (int i = 1; i < ratings.size(); i++){
            if (ratings[i] > ratings[i-1]){
                nums[i] = nums[i-1] + 1;
            }
        }
        for (int i = length - 1; i > 0; i--){
            if (ratings[i-1] > ratings[i]){
                nums[i-1] = max(nums[i-1], nums[i]+ 1);
            }
        }
        return accumulate(nums.begin(), nums.end(), 0);
    }
};

2 区间问题

2.1 Non-overlapping intervals(Medium) 435.无重叠区间

题解:

先按照区间的第二个元素大小排序,然后比较前一个区间的第二个元素和当前区间的第一个元素的大小。边遍历边寻找满足要求的区间。

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        if (intervals.empty()) return 0;
        int size = intervals.size();
        // 按照每个元素的第二个元素的大小排列,因为每个元素右边的元素决定的这个区间的结束。
        sort(intervals.begin(), intervals.end(), [](vector<int>a, vector<int>b){
            return a[1] < b[1];
        });
        int res = 0, prev = intervals[0][1];
        for (int i = 1; i < size; i++){
            if (intervals[i][0] < prev){
                res++;
            } else{
                prev = intervals[i][1];
            }
        }
        return res;
    }
};

3 练习

3.1 Can Place Flowers(Easy) 605.种花问题

题解:

其实就是利用贪心的思想,只有一个点的值为0才能种花,就是要判断这个为0的点左面和右边的点是否都为0,同时考虑两个特殊点,左边界和右边界,因为这两个点只有一个邻居。

class Solution {
public:
    bool canPlaceFlowers(vector<int>& flowerbed, int n) {
        //int temp = flowerbed
        if (flowerbed.size() == 1 && flowerbed[0] == 0) return --n <= 0;
        for (int i = 0; i < flowerbed.size(); i++){
            if (flowerbed[i] == 0){
                if (i == 0){
                    if (flowerbed[i+1] == 0){
                        flowerbed[i] = 1;
                        n--;
                    }
                }else if(i == flowerbed.size() - 1){
                    if (flowerbed[i-1] == 0){
                        flowerbed[i] = 1;
                        n--;
                    }
                }else{
                    if(flowerbed[i-1] == 0 && flowerbed[i+1] ==0){
                        flowerbed[i] = 1;
                        n--;
                    }
                } 
            }
        }
        return n<=0;
    }
};

3.2 Minimum Number of Arrows to Burst Balloons (Medium) 452.用最少数量的箭引爆气球

题解:

和435类似,先进行排序(按照每一个元素的第二个位置的值排序)然后进行循环遍历,判断当前的这个气球的最小值是不是比上一个记录下来的值(这个值用来记录箭射中的第一个气球的最大值,同时这个箭还可能射中后面的气球)大,如果大就不和他公用一个箭,就自己用一个,如果不大就和上一个气球公用一个箭。

public:
    int findMinArrowShots(vector<vector<int>>& points) {
        if (points.empty())  return 0;
        sort(points.begin(), points.end(), [](vector<int> a, vector<int> b){
            return a[1] < b[1];
        });
        int res = 1, prev = points[0][1];
        for (int i = 1; i < points.size(); i++){
            if (points[i][0] > prev){
                res++;
                prev = points[i][1];
            }
        }
        return res;
    }
};

3.3 Partition Labels(Medium) 763.划分字母区间


这道题思路就是参考的官方思路,首先遍历存储所有字母的最大索引值,然后建立两个指针,从前向后开始遍历,用end指针和每一个字母的最大的索引比较,让end等于每一次循环end和当前字母索引的最大值如果end和当前的循环索引相等,那么就存储为一个子序列,然后一次循环。

class Solution {
public:
    vector<int> partitionLabels(string S) {
        // 用哈希表的思想
        int hash_map[26] = {0};
        vector<int> res;
        int start = 0, end = 0;
        // 现存一边每个字母最后出现的索引
        for (int i = 0; i < S.size(); i++){
            hash_map[S[i] - 'a'] = i;
        }
        for (int i = 0; i < S.size(); i++){
            end = max(end, hash_map[S[i] - 'a']);
            if (end == i){
                res.push_back(end - start + 1);
                start = end + 1;
            }
        }
        return res;
    }
};

3.4 Best Time to Buy and Sell stock 2(Easy)122.买卖股票的最佳时机

遍历求和就好,每次计算出差值 当为负数就不做计算,当为正就求和,相当于求max(0, res)

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int res = 0;
        for (int i = 1; i < prices.size(); i++){
            res += max(0, prices[i] - prices[i-1]);
        }
        return res;
    }
};

3.5 406. 根据身高重建队列(中等)

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
       sort(people.begin(), people.end(), [](vector<int> a, vector<int> b){
           if (a[0] == b[0]) return a[1] < b[1];
           else return a[0] > b[0];
       });
       vector<vector<int>> que;
       for (int i = 0; i < people.size(); i++){
           int ki = people[i][1];
           que.insert(que.begin() + ki, people[i]);
       }
       return que;
    }
};

3.6 665.非递减数列(简单)

两次循环,第一次找到一个,第二次如果还有就是false,否则为true。

class Solution {
public:
    bool checkPossibility(vector<int>& nums) {
        if (nums.size() <= 2) return true;
        for (int i = 0; i <= nums.size() - 2; i++){
            if (nums[i] > nums[i+1]){
                if (i == 0){
                    nums[i] = nums[i+1];
                    break;
                }else if (i == nums.size() - 2){
                    // nums[i+1] = nums[i];
                    return true;
                }
                if (nums[i] < nums[i+2] && nums[i-1] <= nums[i]){
                    nums[i+1] = nums[i];
                }else if (nums[i-1] <= nums[i+1] && nums[i+1] <= nums[i+2]){
                    nums[i] = nums[i+1];
                }else return false;
                break;               
            }
        }
        cout << nums.size() << endl;
        for (int i = 0; i <= nums.size() - 2; i++){
            // cout << nums[i] << endl;
            if (nums[i] > nums[i+1]){
                // cout << 1;
                return false;
            }
        }
        return true;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值