力扣算法刷题 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;
    }
};
相关推荐
少许极端2 小时前
算法奇妙屋(四十)-贪心算法学习之路7
java·学习·算法·贪心算法
AlenTech2 小时前
647. 回文子串 - 力扣(LeetCode)
算法·leetcode·职场和发展
py有趣2 小时前
力扣热门100题之合并两个有序链表
算法·leetcode·链表
8Qi82 小时前
LeetCode热题100--45.跳跃游戏 II
java·算法·leetcode·贪心算法·编程
foundbug9993 小时前
基于STM32的步进电机加减速程序设计(梯形加减速算法)
stm32·单片机·算法
北顾笙9803 小时前
day12-数据结构力扣
数据结构·算法·leetcode
凌波粒3 小时前
LeetCode--454.四数相加 II(哈希表)
算法·leetcode·散列表
漫随流水3 小时前
c++编程:D进制的A+B(1022-PAT乙级)
数据结构·c++·算法
tankeven4 小时前
HJ159 没挡住洪水
c++·算法