贪心解题notebook

贪心的本质是选择每一阶段的局部最优,从而达到全局最优。

455. 分发饼干

在这里插入图片描述

class Solution {
public:
    int findContentChildren(vector<int>& g, vector<int>& s) {
        // 从小到大的排序,一一对应
        // wrong:sort(g);
        // wrong:sort(s);
        sort(g.begin(), g.end());
        sort(s.begin(), s.end());
        int index = 0;
        for (int i = 0; i < s.size(); i++) {
            # wrong: if (g[index] <= s[i]) {
            if (index < g.size() && g[index] <= s[i]) {
                index++;
            }
        }
        return index;
    }
};

小结

  • 忘了sort怎么用的了,以及手写排序
  • 下标越界了

376. 摆动序列

在这里插入图片描述

class Solution {
public:

    int wiggleMaxLength(vector<int>& nums) {
        int cur = 0;
        int pre = 0;
        int result = 1;
        for (int i = 0; i < nums.size() - 1; i++) {
            cur = nums[i + 1] - nums[i];
            // wrong: if ((nums[i + 1] - nums[i]) * (nums[i] - nums[index]) < 0)
            if ((pre <= 0 && cur > 0) || (pre >= 0 && cur < 0)) {
                result++;
                pre = cur;
            }
        }
        return result;
    }
};

在这里插入图片描述

小结

  • 必然存在一个波峰
  • 然后只要前一个小于等于0,或前一个大于等于0,当前相反
  • 我错在没考虑等于0的情况

53. 最大子数组和

在这里插入图片描述

class Solution {
public:
    int maxSubArray(vector<int>& nums) {
        // wrong:int result = INT_MIN32;
        int result = INT32_MIN;
        int count = 0;
        for (int i = 0; i < nums.size(); i++) {
            count += nums[i];
            if (result < count) {
                result = count;
            }
            if (count <= 0) {
                count = 0;
            }
        }
        return result;
    }
};

在这里插入图片描述

小结

  • 在思考都是负数的情况时,没有想明白

406. 根据身高重建队列

在这里插入图片描述

class Solution {
public:
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        // 0维从大到小,1维从小到大
        if (a[0] == b[0]) return a[1] < b[1];
        return a[0] > b[0];
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        // 先按照身高从大到小的顺序排列
        // 问题1.排序用什么排
        // 问题2.(->)和(.)的使用差异
        // sort 默认升序
        // 可以自定义cmp、也可以用标准库
        // 二维的自定义cmp
        // wrong
        // sort(people.begin(), people.end(), greater<int>());
        sort(people.begin(), people.end(), cmp);

        // 然后相同身高,按k从小到大
        // wrong
        // for (auto p : people) {
        //     sort(p.begin(), p.end(), less<int>());
        // }

        // 指定位置插入
        // list 和 vector 插入时有点区别
        // list 效率高于 vector
        // 最后重新插入,按照k的值,插入到指定下标
        // vector<vector<int>> que;
        // for (int i = 0; i < people.size(); i++) {
        //     int position = people[i][1];
        //     // 指定位置插入值
        //     que.insert(que.begin() + position, people[i]);
        // }
        // return que;
        list<vector<int>> que;
        for (int i = 0; i < people.size(); i++) {
            int position = people[i][1]; // 插入到下标为position的位置
            // std::list<vector<int>>::iterator it = que.begin();
            auto it = que.begin();
            while (position--) { // 寻找在插入位置
                it++;
            }
            que.insert(it, people[i]);
            // wrong: que.insert(que.begin() + position, people[i]);
        }
        return vector<vector<int>>(que.begin(), que.end());
    }
};

在这里插入图片描述

小结

  • cmp
  • list和vector的insert

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

在这里插入图片描述

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) {
        // 首先进行排序,左边界、升序, 
        sort(points.begin(), points.end(), cmp);
        // 然后比较交叉处
        // 若不交叉,弓箭数++
        // 若交叉,选择右边界小的
        if (points.size() == 0) {
            return 0;
        }
            
        int count = 1;
        for (int i = 1; i < points.size(); i++) {
            // wrong: points[i][0] > points[i - 1][0]
            if (points[i][0] > points[i - 1][1]) {
                count++;
            } else {
                // wrong: min(points[i][1], points[i - 1][0])
                points[i][1] = min(points[i][1], points[i - 1][1]);
            }
        }
        
        return count;
    }
};

在这里插入图片描述

435. 无重叠区间

在这里插入图片描述

class Solution {
private:
    // static
    // const
    // &
    /*
        按照右边界排序,就要从左向右遍历,因为右边界越小越好,只要右边界越小,留给下一个区间的空间就越大,所以从左向右遍历,优先选右边界小的。
    */
    // static bool cmp( vector<int> a, vector<int> b) {
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        //return a[0] < a[0];
        return a[1] < b[1];
    }
public:
    int eraseOverlapIntervals(vector<vector<int>>& intervals) {
        
        if (intervals.size() == 0) {
            return 0;
        }
        sort(intervals.begin(), intervals.end(), cmp);
        int count = 1;
        int end = intervals[0][1];
        for (int i = 1; i < intervals.size(); i++) {
            if (end <= intervals[i][0]) {
                count++;
                end = intervals[i][1];
            }
        }
        return intervals.size() - count;
    }
};

在这里插入图片描述

小结

  • 究竟是按照右边界排序,还是按照左边界排序

763. 划分字母区间

在这里插入图片描述

class Solution {
public:
    vector<int> partitionLabels(string s) {
        int hash[26] = {0};
        // 记录每个字母出现最远的地方
        for (int i = 0; i < s.size(); i++) {
            hash[s[i] - 'a'] = i;
        }
        int left = 0;
        int right = 0;
        vector<int> result;
        for (int i = 0; i < s.size(); i++) {
            right = max(right, hash[s[i] - 'a']);
            if (i == right) {
                result.push_back(right - left + 1);
                left = right + 1;
            }
        }
        return result;
    }
};

在这里插入图片描述

小结

  • 难点在于right=max(right, hash[s[i]-‘a’]);

56. 合并区间

在这里插入图片描述

class Solution {
private:
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        return a[0] < b[0];
    }
public:
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        // 先按从小到大排序,左边
        // 然后比较右边界,选择大的一边
        // 把intervals存入结果,慢慢改变右边界
        vector<vector<int>> result;
        if (intervals.size() == 0) return result;
        sort(intervals.begin(), intervals.end(), cmp);
        result.push_back(intervals[0]);
        for (int i = 1; i < intervals.size(); i++) {
            // wrong:intervals[i - 1][1] >= intervals[i][0]
            if (result.back()[1] >= intervals[i][0]) {
                result.back()[1] = max(result.back()[1], intervals[i][1]);
                
            } else {
                result.push_back(intervals[i]);
            }

        }
        return result;
    }
};

在这里插入图片描述

小结

  • 问题所在:合并比较的是result.back()[1] 和 intervals[i][0]

738. 单调递增的数字

在这里插入图片描述

class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        // 首先确定遍历顺序是从后向前
        // 当 strNum[i-1] > strNum[i] 时,将str[i-1]-1,strNum[i]置为9 
        // 怎么将int n 转换为 string strNum
        // to_string(): 从后到前的取出每个数字,然后逆序输出,注意负数
        // strNum << n
        string strNum = to_string(n);
        int flag = strNum.length();
        for (int i = strNum.length() - 1; i > 0; i--) {
            if (strNum[i - 1] > strNum[i]) {
                strNum[i - 1]--;
                flag = i;
            }
        }
        for (int i = flag; i < strNum.length(); i++) {
            strNum[i] = '9';
        }
        return stoi(strNum);
    }
};

在这里插入图片描述

小结

  • to_string(), stoi()

714. 买卖股票的最佳时机含手续费

在这里插入图片描述

class Solution {
public:
    int maxProfit(vector<int>& prices, int fee) {
        // 分三种情况
        // 1. 买入,也是前面真正的卖出
        // 2. 卖出,但不真正卖出
        // 3. 不操作
        int min = prices[0];
        int result = 0;
        for (int i = 1; i < prices.size(); i++) {
            // 1.
            if (prices[i] < min) {
                min = prices[i];
            }
            // 2.
            if (prices[i] > min + fee) {
                result += prices[i] - min - fee;
                min = prices[i] - fee;
            }
            // 3.
            if (prices[i] > min && prices[i] < min + fee) {
                continue;
            }


        }
        return result;
    }
};

在这里插入图片描述

小结

  • 情况2中,并不是真正的卖出,因为是prices[i]>min, 此时将min更新

968. 监控二叉树

在这里插入图片描述

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
private:
    int result;
    int traversal(TreeNode* cur) {
        // 从下往上遍历(后序)
        // 0:无覆盖
        // 1:摄像头
        // 2:有覆盖

        // 空节点,必须覆盖
        if (cur == NULL) return 2;
        int left = traversal(cur->left);
        int right = traversal(cur->right);

        // 左右只要有一个无覆盖,就增加一个摄像头,并且说明本节点需要一个摄像头
        if (left == 0 || right == 0) {
            result++;
            return 1;
        }
        
        // 左右只要有一个有摄像头,说明本节点被覆盖了
        if (left == 1 || right == 1) {
            return 2;
        }

        // 左右都被覆盖,说明本节点无覆盖
        if (left == 2 && right == 2) {
             return 0;
        }
        return -1;
    }
public:
    int minCameraCover(TreeNode* root) {
        result = 0; 
        if (traversal(root) == 0) {
            result++;
        }
        return result;
    }
};

在这里插入图片描述

小结

  • 空节点设为被覆盖,在叶子节点的父节点装摄像头
  • 隔两个结点放一个摄像头
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值