第16周 算法思想-贪心

算法思想-贪心

利用贪心思想解题的最大难点在于证明贪心的选择是最优的。常用的证明方法:反证法、数学归纳法

不重叠的区间个数

典型的贪心,先按结束时间排序,然后依次选择。
证明:如果不先选结束最早的,选择一个结束第k早的,那么接下来可选的时间范围变为了[k_end,end],1_end < k_end,如果[k_end,end]中答案为m,[1_end,end]的答案肯定大于等于m,所以应该选结束最早的。(i_end表示结束时间排在第i位的活动的结束时间,end表示最晚时间)

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

class Solution {
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        int n = intervals.size();
        if(n == 1)
            return 0;
        
        int left = 0;
        
        sort(intervals.begin(), intervals.end(), cmp);
        
        int max_t = intervals[0][1];
        left += 1;
        for(int i = 1;i < n; i++){
            if(intervals[i][0] >= max_t){
                max_t = intervals[i][1];
                left += 1;
            }
        }
        return n-left;
    }
};

投飞镖刺破气球

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

class Solution {
public:
    int findMinArrowShots(vector<vector<int>>& points) {
        sort(points.begin(), points.end(), cmp);
        
        int ans = 1;
        int end = points[0][1];
        
        for(int i = 1;i < points.size(); i++){
            if(points[i][0] <= end)
                continue;
            end = points[i][1];
            ans += 1;
        }
        
        return ans;
    }
};

根据身高和序号重组队列

已知逆序数数组求原排列

选用list方便进行快速插入

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

class Solution {
public:
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort(people.begin(), people.end(), cmp);
        
        list<vector<int>> q;
        for(int i = 0;i < people.size(); i++){
            list<vector<int>>::iterator it = q.begin();
            int pos = people[i][1];
            while(pos--)
                it++;
            q.insert(it, people[i]);
        }
        
        vector<vector<int>> ans;
        for(auto it: q)
            ans.push_back(it);
        return ans;
    }
};

买卖股票最大的收益

遍历数组,curr表示当前已知的最低价,遇到更低的则更新curr,否则更新profit

买卖股票的最大收益 II

贪心:有钱赚就卖,卖了马上再买

子数组最大和

求和,和为负值后重新开始。

分隔字符串使同种字符出现在一起

统计每个字符串出现的最远位置,遍历字符串的每个字符,如果当前位置前面的所有字符出现的最远位置都没有超过当前位置则可以划分。

class Solution {
public:
    vector<int> partitionLabels(string s) {
        
        int maxpos[26];
        for(int i = 0;i < s.size(); i++)
            maxpos[s[i] - 'a'] = i;
        
        int i = 0, start = 0, end = 0;
        vector<int> ans;
        
        while(i < s.size()){
            end = max(end, maxpos[s[i] - 'a']);
            if(end <= i){
                ans.push_back(end-start+1);
                start = i+1;
            }
            i += 1;
        }
        
        return ans;
        
    }
};

修改一个数成为非递减数组

参考链接:https://leetcode-cn.com/problems/non-decreasing-array/solution/yi-ding-yao-rang-ni-nong-dong-wei-shi-ya-u9te/

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值