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

#738 单调递增的数字

30min 自己想的是O n^2 也能过

int monotoneIncreasingDigits(int n) {
        if(n<10) return n;
        if(n==10) return 9;

        string numstr=to_string(n);
        
        int pos=-1;
        for(int i=0;i+1<numstr.size();i++){
            if(numstr[i+1]<numstr[i] && pos==-1) pos=i;
        }
        if(pos==-1) return n;
        //now has conflict
        while(pos>=0){
            //pos[] -1, after 9
            numstr[pos]=numstr[pos]-1;
            for(int i=pos+1;i<numstr.size();i++) numstr[i]='9';
            if(pos==0) break;  
            if(pos>0){
                if(numstr[pos-1]<=numstr[pos]) break;
                else pos--;
            }
        }
        return stoi(numstr);
    }

补充一个小插曲:初写出来run是TLE,其实TLE也不代表是自己想出来的算法复杂度有问题,直接思路不行。有可能是code某处没写对,死循环了,所以还可以改进对的。然后又出现了和加油站那题一样,在run状态下,某个case TLE 之后,再跑别的case出现不正常不合理的结果,这可能是leetcode编译资源没更新。这时只需要去submit再跑一次就好了,就不会出现诡异的结果了。


改进:每次找到conflict位置后,不用急于把后面都改成9.反正一轮一轮会不断向前更新conflict位置。等找完了更新完毕,再一起把后面都改成9. 而且仔细看看自己的逻辑会发现,不用处理开头那些特殊情况。倒是 10 会变成09,但是 stoi 也还是能变成9的。

于是进行了以上的改进就把 O n ^2 变成了 O n, 变成和随想录一样的了

int monotoneIncreasingDigits(int n) {
        string numstr=to_string(n);
        
        int pos=-1;
        for(int i=0;i+1<numstr.size();i++){
            if(numstr[i+1]<numstr[i] && pos==-1) pos=i;
        }
        if(pos==-1) return n;
        //now has conflict
        while(pos>=0){
            //pos[] -1, after 9
            numstr[pos]=numstr[pos]-1;
            //for(int i=pos+1;i<numstr.size();i++) numstr[i]='9';
            if(pos==0) break;  
            if(pos>0){
                if(numstr[pos-1]<=numstr[pos]) break;
                else pos--;
            }
        }
        //return stoi(numstr);
        for(int i=pos+1;i<numstr.size();i++){
            numstr[i]='9';
        }
        return stoi(numstr);
    }

#968.监控二叉树  Hard

一开始忘了是贪心,当做dp去做了。其实也可以做,也是要用这三种状态

随想录的思路的代码:

int result;
    int traversal(TreeNode* cur) {
        // status num:
        // 0 not covered
        // 1 have cam
        // 2 yes covered

        // !! special: null == covered
        //因为设置成 0 1 都不对
        if (cur == NULL) return 2;

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

        // 情况1
        // 左右节点都有覆盖,那他们就没有摄像头,是间接被覆盖的,不能覆盖别人
        //所以 parent没被覆盖 
        if (left == 2 && right == 2) return 0;

        // 情况2
        //只要有一个孩子没被覆盖,parent就要放摄像头
        if (left == 0 || right == 0) {
            result++;
            return 1;
        }
        // 情况3
        //只要有一个child有摄像头,parent就被覆盖
        if (left == 1 || right == 1) return 2;

        // 这个 return -1 逻辑不会走到这里。
        return -1;
    }
    int minCameraCover(TreeNode* root) {
        
        result = 0;

        // 情况4
        if (traversal(root) == 0) { // root 无覆盖
            result++;
        }
        return result;
    }

思路产生的逻辑:leaf node不能放cam->leaf parent要放 cam -> 往上遍历,child parent 间隔一个放一个cam (这是局部最优)

需要建立以下状态:而且要注意dp是有择优的,但是贪心就是单纯的状态转移

 还有个要点是,空node要设置成被覆盖,才合理(其实我觉得 再弄个数字作为第四种状态,也可以,就是逻辑判断要再复杂一点) 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值