当前位置:   article > 正文

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

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

贪心算法章节理论基础:

https://programmercarl.com/%E8%B4%AA%E5%BF%83%E7%AE%97%E6%B3%95%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html

738.单调递增的数字

题目链接:https://leetcode.cn/problems/monotone-increasing-digits/

思路:

题目要求小于等于N的最大单调递增的整数,从后向前遍历,比如322来说,332 -> 329 -> 299。首先当前数字arr[i]–,然后最后一位给9。

要注意一个点就是,不能直接赋值成9,这里用的是一个start来保存位置,因为比如100,按我们刚刚的算法,他的结果是9,而不是99了。要注意一下这个地方。

class Solution {
    public int monotoneIncreasingDigits(int n) {
        // 从最后一位开始
        char[] arr = String.valueOf(n).toCharArray();
        int start = arr.length;
        for(int i=arr.length-2;i>=0;i--){
            if(arr[i] > arr[i + 1]){
                // arr[i+1] = '9';
                start = i + 1;
                arr[i]--;   // 当前位置减少1
            }
        }
        // 100 -> 99
        for(int i=start;i < arr.length;i++){
            arr[i] = '9';
        }
        return Integer.parseInt(String.valueOf(arr));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

968.监控二叉树

题目链接:https://leetcode.cn/problems/binary-tree-cameras/description/

思路:

摄像头可以覆盖上中下三层,如果把摄像头放在叶子节点上,就浪费的一层的覆盖。

所以我们要从下往上看,局部最优:让叶子节点的父节点安摄像头,所用摄像头最少,整体最优:全部摄像头数量所用最少!

可以使用后序遍历也就是左右中的顺序,这样就可以在回溯的过程中从下到上进行推导了。

下面,来看看这个状态应该如何转移,先来看看每个节点可能有几种状态:

有如下三种:

  • 该节点无覆盖
  • 本节点有摄像头
  • 本节点有覆盖

我们分别有三个数字来表示:

0:该节点无覆盖
1:本节点有摄像头
2:本节点有覆盖

为了让摄像头数量最少,我们要尽量让叶子节点的父节点安装摄像头,这样才能摄像头的数量最少。

因为在遍历树的过程中,就会遇到空节点,那么问题来了,空节点究竟是哪一种状态呢? 空节点表示无覆盖? 表示有摄像头?还是有覆盖呢?

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

那么递归的终止条件应该是遇到了空节点,此时应该返回2(有覆盖)。

// 空节点,该节点有覆盖
if (cur == NULL) return 2;
  • 1
  • 2

主要有如下四类情况:

情况1:左右节点都有覆盖
左孩子有覆盖,右孩子有覆盖,那么此时中间节点应该就是无覆盖的状态了。

情况2:左右节点至少有一个无覆盖的情况
如果是以下情况,则中间节点(父节点)应该放摄像头.

情况3:左右节点至少有一个有摄像头
如果是以下情况,其实就是 左右孩子节点有一个有摄像头了,那么其父节点就应该是2(覆盖的状态).

情况4:头结点没有覆盖
以上都处理完了,递归结束之后,可能头结点 还有一个无覆盖的情况。
在这里插入图片描述
所以递归结束之后,还要判断根节点,如果没有覆盖,result++。

class Solution {
    public List<Integer> partitionLabels(String s) {
        int[] arr = new int[26];
        int len = s.length();
        // 统计每一个字符最后出现的位置
        for(int i = 0;i<len;i++){
            char c = s.charAt(i);
            arr[c-'a'] = i+1;
        }
        int left = 0;
        int right = 0;
        List<Integer> list = new LinkedList<>();
        for(int i=0;i<len;i++){
            // 找到字符最远的右边界
            right = Math.max(right,arr[s.charAt(i)-'a']);   
            if(right == i+1){
                list.add(right - left);
                left = right;
            }
        }
        return list;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/羊村懒王/article/detail/422892
推荐阅读
相关标签
  

闽ICP备14008679号