力扣算法刷题 Day 31 (贪心总结)

56 合并区间

题目链接

添加链接描述

思路

和前面重叠区间的思路相同。这里需要用到vector::back()函数,来获取结果集当前最后区间的右边界。

文章详解

添加链接描述

cpp 复制代码
class Solution {
private:
    static bool cmp(vector<int> a,vector<int>b)
    {
        return a[0] < b[0];
    }
public:
    vector<vector<int>> result;
    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        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++)
        {
            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;
    }
};

738 单调递增的数字

题目链接

添加链接描述

思路

先将数字按位转为字符串,需要用到to_string()和stoi()函数;思考局部最优:当前一位比后一位大时,将前一位减1,后一位变为9,此时为最大。这里需要注意:倘若直接变,之后不管的话,可能会出现前一位和后一位相同,更前一位比后一位大的情况,如100.所以需要记录需要变化的位置,将之后的所有数字变成9.

文章详解

添加链接描述

cpp 复制代码
class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        string strnum = to_string(n);
        int flag = strnum.size();
        for(int i = strnum.size() - 1; i > 0 ; i--)
        {
            if(strnum[i-1] > strnum[i])
            {
                strnum[i-1]--;
                flag = i;
            }
            //cout << strnum[i];
        }
        for(int i = flag; i < strnum.size();i++)
        {
            strnum[i] = '9';
        }

        return stoi(strnum);
    }
};

968 监控二叉树

题目链接

添加链接描述

思路

什么时候需要装摄像头?

  • 左右子节点为叶子节点且也为0。
  • 左孩子或者右孩子为空,另一个为叶子节点;
  • 父节点存在且为0,左右孩子存在(不为叶子节点)且为0
  • 父节点存在且为0,左或右孩子存在(不为叶子节点)且为0

采用什么遍历顺序?

上述情况都要考虑左右孩子,可以使用先根遍历,同时设定一个指针指向其父节点。当满足上述情况时,该节点的值设为1,即被安装摄像头。

初版代码如下:

cpp 复制代码
/**
 * 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 num;
    void travelling(TreeNode* node, TreeNode* father)
    {
        // if(node->left == nullptr && node->right == nullptr)
        // {
        //     return;
        // }
        if(node == nullptr) return;
        else if(node->left && node->left->left == nullptr && node->left->right == nullptr && 
            node->right && node->right->left == nullptr && node->right->right == nullptr)
             //1.左右孩子均为叶子节点
        {
            if(node->val == 0)
            {

            node->val = 1;
            num++;
            }
            return;
        }
        else if((node->left == nullptr && node->right && node->right->left == nullptr && node->right->right == nullptr)
        || (node->right == nullptr && node->left && node->left->left == nullptr && node->left->right == nullptr))
        //2. 左孩子或者右孩子为空,另一个为叶子节点;
        {
            //cout << "!" << endl;
           if(node->val == 0)
            {

            node->val = 1;
            num++;
            }
            return;
        }
        else if(( node->right && node->right->left == nullptr && node->right->right == nullptr)
        || ( node->left && node->left->left == nullptr && node->left->right == nullptr))
        //2. 左孩子或者右孩子为空,另一个为叶子节点;
        {
            //cout << "!" << endl;
           if(node->val == 0)
            {

            node->val = 1;
            num++;
            }
            //return;
        }
        else if((father && father->val == 0) && (node->left || node->right)) //父节点存在且为0,左右孩子存在(不为叶子节点)且为0
        {
            if(node->val == 0)
            {

            node->val = 1;
            num++;
            }
            //return;
            //return;
        }
        
        travelling(node->left,node);
        travelling(node->right,node);

    }
    int minCameraCover(TreeNode* root) {
        if(root == nullptr) return 0;
        if(root->left == nullptr && root->right == nullptr) return 1;
        travelling(root,nullptr);
        return num;
    }
};

无法通过所有测试集。从根节点往下需要考虑的太多。

这时我们转换思维:可不可以从下往上呢?我们给叶子节点的父节点安装摄像头,不给叶子节点安装,之后每个叶子节点向上每隔2个节点安装一个摄像头,保证充分利用!

那么如何每隔两个节点安装呢?

首先节点有3个状态:

  • 无覆盖
  • 有覆盖
  • 有摄像头

分别表示为0,1,2.

而空节点的状态为有覆盖,这样叶子节点的父节点会安装摄像头

本层递归逻辑?

情况1:左右孩子都有覆盖

情况2:左右节点至少有一个无覆盖的情况

如果是以下情况,则中间节点(父节点)应该放摄像头:

left == 0 && right == 0 左右节点无覆盖

left == 1 && right == 0 左节点有摄像头,右节点无覆盖

left == 0 && right == 1 左节点有无覆盖,右节点摄像头

left == 0 && right == 2 左节点无覆盖,右节点覆盖

left == 2 && right == 0 左节点覆盖,右节点无覆盖

情况3:左右节点至少有一个有摄像头

如果是以下情况,其实就是 左右孩子节点有一个有摄像头了,那么其父节点就应该是2(覆盖的状态)

left == 1 && right == 2 左节点有摄像头,右节点有覆盖

left == 2 && right == 1 左节点有覆盖,右节点有摄像头

left == 1 && right == 1 左右节点都有摄像头

情况4:头结点没有覆盖

以上都处理完了,递归结束之后,可能头结点 还有一个无覆盖的情况

文章详解

添加链接描述

cpp 复制代码
// 版本一
class Solution {
private:
    int result;
    int traversal(TreeNode* cur) {

        // 空节点,该节点有覆盖
        if (cur == NULL) return 2;

        int left = traversal(cur->left);    // 左
        int right = traversal(cur->right);  // 右

        // 情况1
        // 左右节点都有覆盖
        if (left == 2 && right == 2) return 0;

        // 情况2
        // left == 0 && right == 0 左右节点无覆盖
        // left == 1 && right == 0 左节点有摄像头,右节点无覆盖
        // left == 0 && right == 1 左节点有无覆盖,右节点摄像头
        // left == 0 && right == 2 左节点无覆盖,右节点覆盖
        // left == 2 && right == 0 左节点覆盖,右节点无覆盖
        if (left == 0 || right == 0) {
            result++;
            return 1;
        }

        // 情况3
        // left == 1 && right == 2 左节点有摄像头,右节点有覆盖
        // left == 2 && right == 1 左节点有覆盖,右节点有摄像头
        // left == 1 && right == 1 左右节点都有摄像头
        // 其他情况前段代码均已覆盖
        if (left == 1 || right == 1) return 2;

        // 以上代码我没有使用else,主要是为了把各个分支条件展现出来,这样代码有助于读者理解
        // 这个 return -1 逻辑不会走到这里。
        return -1;
    }

public:
    int minCameraCover(TreeNode* root) {
        result = 0;
        // 情况4
        if (traversal(root) == 0) { // root 无覆盖
            result++;
        }
        return result;
    }
};
相关推荐
KaMeidebaby1 天前
卡梅德生物技术快报|PD1 单克隆抗体定制配套 N 糖全谱质控开发
前端·人工智能·算法·数据挖掘·数据分析
8Qi81 天前
LeetCode 235. 二叉搜索树的最近公共祖先(LCA)
算法·leetcode·二叉树·递归·二叉搜索树·lca·迭代
bIo7lyA8v1 天前
算法稳定性分析中的随机扰动建模的技术8
算法
科研online1 天前
基于多源数据和XGBoost-SHAP分析中国大陆绿地碳汇空间变异影响因素的非线性相关性与尺度差异
算法·学习方法
Cthy_hy1 天前
拓扑排序超详解:原理 + Kahn 贪心算法
python·算法·贪心算法
三品吉他手会点灯1 天前
C语言学习笔记 - 43.运算符与表达式 - 运算符1 - 运算符的分类和简单介绍
c语言·笔记·学习·算法
VkN2X2X4b1 天前
算法复杂度的实验验证与误差分析的技术8
算法
其利天下技术1 天前
风扇灯无刷电机自适应算法实战指南
算法·cocos2d·无刷电机自适应算法·bldc驱动自适应算法·其利无刷电机驱动算法
8Qi81 天前
LeetCode 494:目标和(Target Sum)—— 题解 ✅
算法·leetcode·职场和发展·动态规划·01背包
hujinyuan201601 天前
2026年3月 中国电子学会青少年软件编程(Python)三级考试试卷 真题及答案
java·python·算法