算法学习day31-贪心算法

合并区间

核心思路

  • 还是重叠问题, 判断区间边界合并就行

    java 复制代码
    public int[][] merge(int[][] intervals) {
        Arrays.sort(intervals, Comparator.comparing(a -> a[0]));
        int preLeft = intervals[0][0];
        int preRight = intervals[0][1];
        List<int[]> res = new ArrayList<>();
        for (int i = 1; i < intervals.length; i++) {
            int left = intervals[i][0];
            int right = intervals[i][1];
            if (preRight >= left) {
                preRight = Math.max(preRight, right);
            } else {
                res.add(new int[]{preLeft, preRight});
                preRight = right;
                preLeft = left;
            }
        }
        res.add(new int[]{preLeft,preRight});
        return res.toArray(new int[res.size()][]);
    }

单调递增的数字

核心思路

  • 要找到核心的规律, 当出现i-1 > i的时候, i就要变成9, [i-1]的值--,比如98->89,4321->4319->4299->3999

  • 需要注意的是, 如果是1421这种, 实际上1399是最大的单调递增数字, 也就是出现i-1>i的时候, i后面的所有数组都要变成9

    java 复制代码
    public static int monotoneIncreasingDigits(int n) {
        String numStr = String.valueOf(n);
        char[] charArray = numStr.toCharArray();
        int start = charArray.length;
        for (int i = charArray.length - 1; i > 0; i--) {
            int curNum = charArray[i];
            int preNum = charArray[i - 1];
            if (preNum > curNum) {
                start = i;
                charArray[i - 1]--;
            }
        }
        for (int i = start; i < charArray.length; i++) {
            charArray[i] = '9';
        }
        return Integer.parseInt(String.valueOf(charArray));
    }

监控二叉树

核心思路

  • 观察二叉树结构不难发现, 从叶子节点开始往上放摄像头, 是最能节省监控的, 这就需要用到后续遍历, 先判断左右节点状态, 再处理中节点状态

  • 每个节点会存在3个状态

    • 1:该节点有摄像头
    • 2:该节点被摄像头范围覆盖
    • 3:该节点没有被摄像头范围覆盖
  • 那么就能根据左右节点的状态, 来推断当前节点应该处于什么状态

    • 左右节点, 其中一个没有被摄像头覆盖, 那么当前节点必须放一个监控1:有摄像头
    • 左右节点, 其中一个是摄像头, 那么当前节点就是2:被摄像头覆盖
    • 左右节点, 都被摄像头范围覆盖, 但又不是摄像头, 那说明左右节点的各个子节点存在摄像头, 那么当前节点就不能放摄像头, 浪费了, 应该处于3:未被监控状态
  • 需要注意一点是, 根节点有可能存在一种情况, 就是两个子节点都处于2:被覆盖状态, 那根节点就是3:未被监控状态, 需要额外处理一下

    java 复制代码
    //从根节点往上排, 左右中 后续遍历, 这个我想到了
    //但是怎么计算摄像头数量没太大思路
    //情况1: 该节点是摄像头
    //情况2: 该节点已经被摄像头监控范围覆盖
    //情况3: 该节点还没有被摄像头监控范围覆盖
    //1: 有摄像头 2:已经被覆盖 3: 没有被覆盖
    private int count = 0;
    public int minCameraCover(TreeDay1.TreeNode root) {
        int status = findCamera(root);
        if(status == 3){
            count++;
        }
        return count;
    }
    public int findCamera(TreeDay1.TreeNode node){
        //如果节点为空, 则认为是已经被覆盖状态
        if(node == null){
            return 2;
        }
        int left = findCamera(node.left);
        int right = findCamera(node.right);
        //情况1: 左右有一个没被覆盖 当前节点需要放摄像头
        if(left == 3 || right == 3){
            //摄像头数量++
            count++;
            return 1;
        }
        if(left == 1 || right == 1){
            return 2;
        }
        return 3;
    } 

复习

二分查找

  • 二分法, 就是双指针, 找一个中间下标, 根据中间下标判断在左右区间哪里, 这里要考虑好区间定义, 左闭右开还是左闭右闭

    java 复制代码
    public int search(int[] nums, int target) {
        //左闭右开区间, 则 左<=x<右, 左不可能=右
        int left = 0;
        int right = nums.length;
        while (left < right) {
            int mid = left + (right - left) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            if (nums[mid] < target) {
                //在右区间
                left = mid + 1;
            } else {
                //在左区间, 因为是左闭右开, 所以right=mid即可
                right = mid;
            }
        }
        return -1;
    }

暴力移除

  • 快慢指针, 快指针负责遍历全部元素, 慢指针指向最末尾的 != target的下标

    java 复制代码
    public int removeElement(int[] nums, int val) {
        //快慢指针, 快指针负责遍历所有, 慢指针负责指向最末尾的不=val的下标, 该题中 for循环的i就相当于快指针
        int left = 0;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] != val){
                nums[left] = nums[i];
                left++;
            }
        }
        return left;
    }

有序数组的平方

  • 首先, nums是递增的, 且会有负数

  • 要根据平方值排序, 那么实际上就是绝对值越大, 平方数就一定越大

  • 而负数的绝对值越大, 原值就越小, 在数据位置就越靠左

  • 正数越大就越靠右, 所以该题就可以用双指针, 比较左右边界的平方值, 将最大的加到newRes里, 并前移或后移下标即可

    java 复制代码
    public int[] sortedSquares(int[] nums) {
        //首先, nums是递增的, 且可能有负数
        //如果有负数, 那么实际上, 负负得正, 绝对值越大, 那么平方值也就越大, 也就是说, 只需要比较nums的左右边界的数字谁更大就行
        //左闭右闭
        int left = 0;
        int right = nums.length - 1;
        int[] res = new int[nums.length];
        int index = nums.length - 1;
        while(left <= right){
            int leftNum = nums[left] * nums[left];
            int rightNum = nums[right] * nums[right];
            if(leftNum < rightNum){
                res[index--] = rightNum;
                right--;
            }else{
                res[index--] = leftNum;
                left++;
            }
        }
        return res;
    }
相关推荐
爱学习的阿磊2 小时前
C++代码冗余消除
开发语言·c++·算法
YuTaoShao2 小时前
【LeetCode 每日一题】2976. 转换字符串的最小成本 I
算法·leetcode·职场和发展
进阶小白猿2 小时前
Java技术八股学习Day29
学习
蒟蒻的贤2 小时前
滑动窗口策略
算法
闫记康2 小时前
linux配置ssh
linux·运维·服务器·学习·ssh
闪电麦坤953 小时前
Leecode热题100:矩阵置零(矩阵)
线性代数·算法·矩阵
浅念-3 小时前
C语言——双向链表
c语言·数据结构·c++·笔记·学习·算法·链表
Wh-Constelltion3 小时前
【PQ分解法潮流计算(matlab版)】
算法·matlab
lxl13073 小时前
学习C++(5)运算符重载+赋值运算符重载
学习