代码随想录day32|738单调递增的数字968监控二叉树|01笔记

122 阅读2分钟
  • 738单调递增的数字

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 可以利用字符串转换获得数字的位数,然后根据位数的循环得到各个位的余数,然后分别讨论相邻数字的关系,再依靠位数次序构建答案。难点在于边界条件的建立。
  • 讲解观后感

  • 可以直接使用整数数组,这样就可以直接比较每个每个位置的数字了。
  • 以98为例:一旦出现strNum[i - 1] > strNum[i]的情况(非单调递增),首先想让strNum[i - 1]--,然后strNum[i]给为9,这样这个整数就是89,即小于98的最大的单调递增整数。
  • 以从后向前的便利过程就可以通过局部最优推导出全局最优
  • 解题代码

  •     func monotoneIncreasingDigits(N int) int {
            s := strconv.Itoa(N)//将数字转为字符串,方便使用下标
            ss := []byte(s)//将字符串转为byte数组,方便更改。
            lenth := len(ss)
            if lenth <= 1 {
                return N
            }
            for i := lenth-1; i > 0; i-- {
                if ss[i-1] > ss[i] {   //前一个大于后一位,前一位减1,后面的全部置为9
                    ss[i-1] -= 1
                    for j := i; j < lenth; j++ {   //后面的全部置为9
                        ss[j] = '9'
                    }
                } 
            }
            res, _ := strconv.Atoi(string(ss))
            return res 
        }
    
  • 986监控二叉树

  • 代码随想录 (programmercarl.com)
  • 第一印象

  • 自己画了一下树,监控节点监控子节点时可以监控两个节点,而只能向上监控一个节点,并且每向下一层,理论上的叶子节点就会增加,因此监控节点也许应尽量靠近根部。
  • 讲解观后感

  • 因为头结点放不放摄像头也就省下一个摄像头, 叶子节点放不放摄像头省下了的摄像头数量是指数阶别的。
  • **所以我们要从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!**从下往上但是是从叶子结点的上一层开始。
  • 如何隔两个节点放一个摄像头

  • 我们分别有三个数字来表示:
  • 0:该节点无覆盖
  • 1:本节点有摄像头
  • 2:本节点有覆盖
  • 因为叶子节点的两个空节点为有覆盖时,才好跳过叶子结点放置监控,所以空节点状态应该成为有覆盖
  • 具体情况的判断建议去看看卡尔的推导。
  • 解题代码

  • c++
  •     // 版本一
        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;
            }
        };
        
        // 版本二
        class Solution {
        private:
            int result;
            int traversal(TreeNode* cur) {
                if (cur == NULL) return 2;
                int left = traversal(cur->left);    // 左
                int right = traversal(cur->right);  // 右
                if (left == 2 && right == 2) return 0;
                else if (left == 0 || right == 0) {
                    result++;
                    return 1;
                } else return 2;
            }
        public:
            int minCameraCover(TreeNode* root) {
                result = 0;
                if (traversal(root) == 0) { // root 无覆盖
                    result++;
                }
                return result;
            }
        };
        
    
  • golang
  •     const inf = math.MaxInt64 / 2
        
        func minCameraCover(root *TreeNode) int {
            var dfs func(*TreeNode) (a, b, c int)
            dfs = func(node *TreeNode) (a, b, c int) {
                if node == nil {
                    return inf, 0, 0
                }
                lefta, leftb, leftc := dfs(node.Left)
                righta, rightb, rightc := dfs(node.Right)
                a = leftc + rightc + 1
                b = min(a, min(lefta+rightb, righta+leftb))
                c = min(a, leftb+rightb)
                return
            }
            _, ans, _ := dfs(root)
            return ans
        }
        
        func min(a, b int) int {
            if a <= b {
                return a
            }
            return b
        }