合并区间
核心思路
-
还是重叠问题, 判断区间边界合并就行
javapublic 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
javapublic 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; }
复习
二分查找
-
二分法, 就是双指针, 找一个中间下标, 根据中间下标判断在左右区间哪里, 这里要考虑好区间定义, 左闭右开还是左闭右闭
javapublic 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的下标
javapublic 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里, 并前移或后移下标即可
javapublic 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; }