代码随想录-刷题第三十七天

代码随想录-刷题第三十七天

738. 单调递增的数字

题目链接:738. 单调递增的数字

思路:从后向前遍历,如果前一位大于当前位,就让前一位减一,记录当前位的下标,遍历结束后,从记录的下标开始往后都要变成9。

**局部最优:**遇到strNum[i - 1] > strNum[i]的情况,让strNum[i - 1]--,然后strNum[i]给为9,可以保证这两位变成最大单调递增整数。

**全局最优:**得到小于等于N的最大单调递增的整数。

这里使用字符数组来进行操作

class Solution {
    public int monotoneIncreasingDigits(int n) {
        String s = String.valueOf(n);
        char[] chars = s.toCharArray();
        // 用来标记赋值9从哪里开始
        // 设置为这个默认值,为了防止第二个for循环在start没有被赋值的情况下执行
        int start = s.length();
        for (int i = s.length() - 2; i >= 0; i--) {
            if (chars[i] > chars[i + 1]) {
                chars[i]--;
                start = i + 1;
            }
        }
        for (int i = start; i < s.length(); i++) {
            chars[i] = '9';
        }
        return Integer.parseInt(String.valueOf(chars));
    }
}

968. 监控二叉树

题目链接:968. 监控二叉树

思路:可以找到规律,叶子节点是一定不能存放摄像头的,因为一个摄像头可以监测三层的节点,如果放在叶子节点上就少了一层,由此可以确定遍历顺序位自底向上的后序遍历。可以设0为当前节点无覆盖,1为当前节点有摄像头,2为当前节点有覆盖。

**局部最优:**让叶子节点的父节点安摄像头,所用摄像头最少;

**全局最优:**全部摄像头数量所用最少!

空节点不能是无覆盖的状态,这样叶子节点就要放摄像头了,空节点也不能是有摄像头的状态,这样叶子节点的父节点就没有必要放摄像头了,而是可以把摄像头放在叶子节点的爷爷节点上。

所以空节点的状态只能是有覆盖,这样就可以在叶子节点的父节点放摄像头了

class Solution {
    int res = 0;
    
    public int minCameraCover(TreeNode root) {
        // 情况4 对根节点的状态做检验,防止根节点是无覆盖状态
        if(traversal(root) == 0) {
            res++;
        }
        return res;
    }
    /**
       节点的状态值:
       0 表示 无覆盖 
       1 表示 有摄像头
       2 表示 有覆盖 
       后序遍历,根据左右节点的情况,来判读当前节点的状态
     */
    private 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) {
            // 状态值为 1 摄像头数 +1
            res++;
            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;
    }
}

在以上代码的基础上,再进行精简,代码如下:

其实就是在之前版本的基础上,使用else把一些情况直接覆盖掉

class Solution {
    int res = 0;

    public int minCameraCover(TreeNode root) {
        // 对根节点的状态做检验,防止根节点是无覆盖状态
        if (traverse(root) == 0) res++;
        return res;
    }

    private int traverse(TreeNode cur) {
        if (cur == null) return 2;
        int left = traverse(cur.left);
        int right = traverse(cur.right);
        // 如果左右节点都覆盖了的话,那么本节点的状态就应该是无覆盖,没有摄像头
        if (left == 2 && right == 2) return 0;
        else if (left == 0 || right == 0) {
            // 状态值为 1 摄像头数 +1;
            res++;
            return 1;
        } else return 2;
    }
}

贪心算法总结

贪心算法总结篇


你可能感兴趣的:(数据结构,数据结构,算法,java,leetcode,贪心算法)