代码随想录算法训练营第37天|738.单调递增的数字*、968.监控二叉树*

文章讲述了如何使用C++实现两个编程问题:将给定的整数转换为单调递增的数字序列,通过贪心算法优化;以及在二叉树中放置最少数量的摄像头以覆盖所有节点,采用递归方法解决。
摘要由CSDN通过智能技术生成

738.单调递增的数字*

力扣题目链接

代码

示例代码
class Solution {
public:
    int monotoneIncreasingDigits(int N) {
        string strNum = to_string(N);
        // flag用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在flag没有被赋值的情况下执行
        int flag = strNum.size();
        for (int i = strNum.size() - 1; i > 0; i--) {
            if (strNum[i - 1] > strNum[i] ) {
                flag = i;
                strNum[i - 1]--;
            }
        }
        for (int i = flag; i < strNum.size(); i++) {
            strNum[i] = '9';
        }
        return stoi(strNum);
    }
};

思路

  1. 将整数转换成字符串:首先,这个解决方案将输入的整数 N 转换成字符串 strNum。这样做的好处是可以很容易地访问和修改数字的每一位。

  2. 初始化标记位:接着,定义了一个整数变量 flag 作为标记位,用来记录从哪一位开始将后面的所有数字赋值为 9。初始时,flag 被设置为 strNum.size(),即字符串的长度,这是为了处理一些特殊情况,确保即使没有位需要修改,第二个循环也不会执行任何操作。

  3. 从后向前遍历数字:然后,使用一个 for 循环从后向前遍历字符串中的数字,即从最低位到最高位。这个过程中,如果发现当前位的数字小于它前一位的数字(即,strNum[i - 1] > strNum[i]),就将前一位的数字减 1(strNum[i - 1]--),并将标记位 flag 更新为当前位置 i。这个步骤是贪心算法的关键,它确保了减小的数字尽可能地小,而且只修改必要的位。

  4. 修改标记位之后的数字:第一个循环完成后,第二个 for 循环从标记位 flag 开始,将这一位及其后面的所有数字赋值为 9。这样做是为了保证结果是单调递增的,并且尽可能大。

  5. 将修改后的字符串转换回整数并返回:最后,使用 stoi(strNum) 将修改后的字符串转换回整数,并将其作为结果返回。

968.监控二叉树*

力扣题目链接

代码

示例代码
// 版本一
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;
    }
};

思路

此时,大体思路就是从低到上,先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。

  • 5
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值