算法学习 | day32/60 单调递增的数字/监视二叉树

一、题目打卡

        1.1 单调递增的数字

        题目链接:. - 力扣(LeetCode)

// class Solution {
// public:
//     bool check(int n, int& pre, int &ind){
//         while(n>0){
//             int m = n % 10;
//             if(m == pre) ind--;
//             if(m > pre){
//                 ind--; // 要不满足递增要求的后一位开始减,如果减去的是m这个位,可能会减多,比如32,减m就是22,实际应该减到29
//                 return false;
//             }
//             pre = m;
//             n = n / 10;
//             ind++;
//         }
//         return true;
//     }
//     int monotoneIncreasingDigits(int n) {

//         // cout << check(253,3) ? true : false;

//         // 这样逻辑没有问题,但是会超时
//         // while(n > 0){
//         //     if(n / 10 == 0) return n;
//         //     int pre = n % 10;
//         //     if(check(n,pre)) return n;
//         //     n--;
//         // }
//         while(n > 0){
//             if(n / 10 == 0) return n;
//             int pre = n % 10;
//             int ind = 0; // 记录开始不满足递增要求的位数
//             if(check(n,pre,ind)) return n;
//             else n = n - pow(10,ind);
//             // n--;
//         }
        
//         return -1; 
//     }
// };


class Solution {
public:
    int monotoneIncreasingDigits(int n) {
        if(n / 10 == 0) return n;

        string nString = to_string(n);
        // bool flag[nString.size()]{false};
        int flag = nString.size(); // 标记需要变9的起始位置
        for(int i = nString.size() - 1; i > 0; i--){
            // 不用一直减,只要标记一下当前位,后面让这个后面都等于9就一定满足
            // while(nString[i-1] > nString[i]) nString[i-1]--;
            if(nString[i-1] > nString[i]){
                nString[i-1]--;
                flag = i;
            }
        }
        for(int i = flag;i < nString.size();i++){
            nString[i] = '9';
        }
        return stoi(nString);
    }
};

        这个题目我想了两种暴力的解法,最简单的思想肯定是不断减 n,直到找到合适的,对于这个减 n 的方法,最粗暴的肯定是每次减1 ,但是不出所料超时,然后我考虑了一种,统计出现不满足递增数字的位置,然后从这个位置开始递减,但是我发现这样其实也会超时,所以看了答案的解法。

        答案的思想还是比较巧妙的,我认为理解主要分为两个方面,首先是相邻位置被标记不满足递增条件的位置,其实对于后面那一位来说,直接更新为 9 就可以了,因为这样不管递推到多少步,始终都是满足递增的条件的;其次是需要进行标记的处理,我一开始考虑能不能每次就变成9,但对于 100 这种数字,就会出现最后结果变成 90 的情况,所以其实需要从标记的位置开始一直到最后都要变成 9 ,而且也不能只是在每一次遇到相邻更大的时候直接变9,比如:

        for(int i = nString.size() - 1; i > 0; i--){
            // 不用一直减,只要标记一下当前位,后面让这个后面都等于9就一定满足
            // while(nString[i-1] > nString[i]) nString[i-1]--;
            if(nString[i-1] >= nString[i]){
                nString[i-1]--;
                nString[i] = '9';
                // flag = i;
            }
        }

        这样处理不了 101 这种,最后返回的结果会是 91,所以核心的思想其实还是贪心,要让后面所有的都更大。

        1.2 监控二叉树(答案思路)

        题目链接:. - 力扣(LeetCode)

class Solution {
public:
    int res = 0;
    int recur(TreeNode* root){
        if(!root) return 2; //空节点,标记为已覆盖

        int res1 = recur(root->left);
        int res2 = recur(root->right);
        
        if(res1 == 2 && res2 == 2){
            return 0; // 此节点下面两个节点都被覆盖
        }
        if(res1 == 0 && res2 == 0){
            res++;
            return 1; // 此节点下面两个节点都被覆盖
        }

        if((res1 == 0 && res2 == 1) || (res1 == 1 && res2 == 0)){
            res++;
            return 1;
        }

        if(res1 == 1 || res2 == 1) return 2;

        // if((res1 == 1 && res2 == 2) || (res1 == 2 && res2 == 1)){
        //     return 2;
        // }

        // 2 和 0
        if(res1 == 2 || res2 == 2){
            res++;
            return 1; // 这里装摄像头,
        }
        return -1; // 不会走到这里
    }
    int minCameraCover(TreeNode* root) {
        int ret = recur(root);
        if(!ret) res++; // 这里需要注意,如果说最后头结点返回的是0,说明头结点并没有被覆盖到,所以头结点需要重新+1
        return res;
    }
};

        没写出来,看了答案以后自己写的,感觉这个题目难点在处理二叉树的返回值,其实只要逻辑理清楚了,也不是特别复杂,关键的就是考虑好所有的组合返回去的情况(00 01 02 11 12 22),然后分别处理就行了,有一个细节需要注意的是,如果最后返回的是0,那么说明头结点没有被覆盖到,那么就需要最后的结果上再加1。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值