0
点赞
收藏
分享

微信扫一扫

springBoot项目使用Elasticsearch教程

四月天2021 01-17 18:00 阅读 10
算法c++

代码随想录算法训练营

—day31

文章目录


前言

今天是算法营的第31天,希望自己能够坚持下来!
今日任务:
● 56. 合并区间
● 738.单调递增的数字
● 968.监控二叉树


一、 56. 合并区间

思路:
1.先对区间以左边界进行排序
2.遍历区间,重叠的就对区间进行合并,更新右边界;不重叠的直接放入结果集
这里有个技巧,把第一个区间直接放入结果集,然后遍历的时候直接在结果集中进行合并区间

class Solution {
public:
    // static bool cmp(const vector<int>& a, const vector<int>& b) {
    //     return a[0] < b[0];
    // }
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> result;
        if (intervals.size() == 0) return result;
        //用lambda表达式
        sort(intervals.begin(), intervals.end(), [](const vector<int>& a, const vector<int>& b) {return a[0]<b[0];});
        
        //第一个区间直接放入结果集,之后在结果集中进行合并
        result.push_back(intervals[0]);

        for (int i = 1; i < intervals.size(); i++) {
            if (intervals[i][0] <= result.back()[1]) { //重叠
                //合并区间,就是更新结果集里面的右边界,左边界已经按大小排序了,只有右边界需要判断取最大值
                result.back()[1] = max(intervals[i][1], result.back()[1]);
            } else {
                result.push_back({intervals[i][0], intervals[i][1]}); //不重叠
            }
        }

        return result;
    }
};

二、738. 单调递增的数字

思路:

  1. 将数字转成字符串来处理
  2. 后序遍历,如果左边数字比当前数字大,记录当前数字位置flag,并且左边数字-1
  3. 记录的flag及以后的数字都变成9

代码如下:

class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        string s = to_string(n); //转成字符串来处理

        int flag = s.size(); //记录需要变成9的数字位置
        for (int i = s.size() - 1; i > 0; i--) { //后序遍历,一直到第二个数字
            if (s[i - 1] > s[i]) { //左边数字比右边大
                flag = i;
                s[i - 1]--; //左边的数字-1,后面的数字全部变成9
            }
        }

        //flag位置及后面的数字全部变成9
        for (int i = flag; i < s.size(); i++) {
            s[i] = '9';
        }

        return stoi(s);
    }
};

三、968.监控二叉树

思路:
整体思路是让叶子节点的父节点放监控,可以覆盖到叶子节点和父节点的父节点两层。

定义二叉树节点的三种状态:
0.无覆盖
1.有监控
2.有覆盖

思考空节点是什么状态:
空节点需要返回2有覆盖,因为空节点如果返回0和1都会影响“让叶子节点的父节点放监控”这个最初的设定。

思考遍历顺序:
需要左右节点反馈结果给中间节点,使用后序遍历。

递归三部曲:
1.递归的参数和返回值:参数是节点,返回值是自定义的三种节点状态(0,1,2)
2.终止条件:遇到空节点终止。
3.单层递归逻辑:
有三种情况:
情况一:左右节点都有覆盖,那么当前节点无覆盖,需要当前节点的父节点放监控,返回0
情况二:左右任一节点无覆盖,那么当前节点都需要放监控,返回1(result++)
情况三:左右任一节点有监控,那么当前节点就是有覆盖,返回2
还有一种情况,情况四:到根节点的时候返回的是无覆盖,本来需要在当前节点的父节点放监控的,但是根节点已经没有父节点了,那么需要在根节点也放一个监控。
代码如下:

/**
 * 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 {
public:
    int result;
    //定义三种状态,0:无覆盖,1:有摄像头 2:有覆盖
    //叶子节点往上遍历,使用后序遍历(左右中)
    //叶子节点的父节点放摄像头
    int traversal(TreeNode* root) {
        //空节点返回2有覆盖
        if (root == nullptr) return 2;

        int left = traversal(root->left);
        int right = traversal(root->right);
        
        //1.左右节点都有覆盖,当前节点无覆盖,返回0(父节点安装摄像头)
        if (left == 2 && right == 2) return 0;
        //2.左右节点任意一个无覆盖,当前节点安装摄像头,返回1
        if (left == 0 || right == 0) {
            result++;
            return 1;
        }
        //3.左右节点任意一个有摄像头,当前节点有覆盖,返回2
        if (left == 1 || right == 1) return 2;

        return -1;
    }

    int minCameraCover(TreeNode* root) {
        result = 0;
        //4.根节点返回0,本来需要在其父节点安装摄像头来覆盖的,需要加多一个摄像头在根节点
        if (traversal(root) == 0) result++;

        return result;
    }
};

总结

贪心算法终于结束了,之前没接触过贪心算法,学完这一章后受益匪浅。每次看题目都会不禁“啊?”,然后看完题解又会有种茅塞顿开的感觉!

明天继续加油!

举报

相关推荐

0 条评论