算法训练营第三十七天|738.单调递增的数字、968.监控二叉树、146. LRU 缓存

74 阅读1分钟

738. 单调递增的数字

Integer.parseInt 方法用于将一个字符串转换为一个整数(int 类型)。

String.valueOf 方法在 Java 中用于将其他类型的数据转换为字符串(String 类型)。

class Solution {
    public int monotoneIncreasingDigits(int n) {
        String s = String.valueOf(n);
        char[] chars = s.toCharArray();
        int start = s.length(); // start 记录要从哪个位置开始将其后所有数字修改为9
        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. 监控二叉树

摄像头可以覆盖上中下三层,如果把摄像头放在叶子节点上,就浪费的一层的覆盖。所以把摄像头放在叶子节点的父节点位置,才能充分利用摄像头的覆盖面积。

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

此时,大体思路就是从低到上,先给叶子节点父节点放个摄像头,然后隔两个节点放一个摄像头,直至到二叉树头结点。

class Solution {
    int res;
    private int traverse(TreeNode curr){
        /**
            0:该节点无覆盖
            1:本节点有摄像头
            2:本节点有覆盖
        */

        // 空节点,记为有覆盖
        if(curr == null)return 2;

        int left = traverse(curr.left);
        int right = traverse(curr.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){
            // 只要左右孩子至少一个无覆盖,父节点应该放摄像头
            res++;
            return 1;
        }

        // 情况3
        // left == 1 && right == 2 左节点有摄像头,右节点有覆盖
        // left == 2 && right == 1 左节点有覆盖,右节点有摄像头
        // left == 1 && right == 1 左右节点都有摄像头
        if(left ==1 || right == 1)return 2;

        // 逻辑不会走到这个 -1 这里
        return -1;
    }
    public int minCameraCover(TreeNode root) {
        res = 0;
        // 情况4
        if(traverse(root) == 0){
            // 左右孩子都有覆盖,但根节点无覆盖,单独加一个摄像头
            res++;
        }

        return res;
    }
}

146. LRU 缓存

自己多做了一题,和贪心没有关系,是一道模拟过程的题,顺便也记录下来。

class LRUCache {
    int capacity;
    LinkedHashMap<Integer, Integer> cache = new LinkedHashMap<>();

    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        if(!cache.containsKey(key))return -1;

        // 变成常用
        makeRecent(key);
        return cache.get(key);
    }
    
    public void put(int key, int value) {
        // 如果本身有key-value,新的value覆盖旧的值
        if(cache.containsKey(key)){
            // 修改key的值
            cache.put(key, value);
            // 把key变为常用
            makeRecent(key);
            return;
        }

        if(cache.size() >= capacity){
            // 链表头部就是最久未使用的 key
            int oldestKey = cache.keySet().iterator().next();
            cache.remove(oldestKey);
        }

        // 新的key-value添加到链哈希表尾
        cache.put(key, value);
    }

    private void makeRecent(int key){
        int val = cache.get(key);
        // 重新添加到队尾
        cache.remove(key);
        cache.put(key, val);
    }
}