image.png
对我来讲难度爆炸的一场,t2边界处理太麻烦了,做到后面属于是脑子不清楚了

6116. 计算布尔二叉树的值

给你一棵 完整二叉树 的根,这棵树有以下特征:

  • 叶子节点 要么值为 0 要么值为 1 ,其中 0 表示 False ,1 表示 True 。
  • 非叶子节点 要么值为 2 要么值为 3 ,其中 2 表示逻辑或 OR ,3 表示逻辑与 AND 。

计算 一个节点的值方式如下:

  • 如果节点是个叶子节点,那么节点的 为它本身,即 True 或者 False 。
  • 否则,计算 两个孩子的节点值,然后将该节点的运算符对两个孩子值进行 运算

返回根节点_ _root 的布尔运算值。
完整二叉树 是每个节点有 0 个或者 2 个孩子的二叉树。
叶子节点 是没有孩子的节点。

示例 1:
image.png
输入:root = [2,1,3,null,null,0,1] 输出:true 解释:上图展示了计算过程。 AND 与运算节点的值为 False AND True = False 。 OR 运算节点的值为 True OR False = True 。 根节点的值为 True ,所以我们返回 true 。
示例 2:
输入:root = [0] 输出:false 解释:根节点是叶子节点,且值为 false,所以我们返回 false 。

提示:

  • 树中节点数目在 [1, 1000] 之间。
  • 0 <= Node.val <= 3
  • 每个节点的孩子数为 0 或 2 。
  • 叶子节点的值为 0 或 1 。
  • 非叶子节点的值为 2 或 3 。

思路:
后序遍历

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode() {}
  8. * TreeNode(int val) { this.val = val; }
  9. * TreeNode(int val, TreeNode left, TreeNode right) {
  10. * this.val = val;
  11. * this.left = left;
  12. * this.right = right;
  13. * }
  14. * }
  15. */
  16. class Solution {
  17. public boolean evaluateTree(TreeNode root) {
  18. return dfs(root) == 1 ? true : false;
  19. }
  20. int dfs(TreeNode root) {
  21. if (root.val == 1 || root.val == 0)
  22. return root.val;
  23. int l = dfs(root.left);
  24. int r = dfs(root.right);
  25. if (root.val == 2)
  26. return l | r;
  27. else return l & r;
  28. }
  29. }

6117. 坐上公交的最晚时间

给你一个下标从 0 开始长度为 n 的整数数组 buses ,其中 buses[i] 表示第 i 辆公交车的出发时间。同时给你一个下标从 0 开始长度为 m 的整数数组 passengers ,其中 passengers[j] 表示第 j 位乘客的到达时间。所有公交车出发的时间互不相同,所有乘客到达的时间也互不相同。
给你一个整数 capacity ,表示每辆公交车 最多 能容纳的乘客数目。
每位乘客都会搭乘下一辆有座位的公交车。如果你在 y 时刻到达,公交在 x 时刻出发,满足 y <= x 且公交没有满,那么你可以搭乘这一辆公交。最早 到达的乘客优先上车。
返回你可以搭乘公交车的最晚到达公交站时间。你 不能 跟别的乘客同时刻到达。
注意:数组 buses 和 passengers 不一定是有序的。

示例 1:
输入:buses = [10,20], passengers = [2,17,18,19], capacity = 2 输出:16 解释: 第 1 辆公交车载着第 1 位乘客。 第 2 辆公交车载着你和第 2 位乘客。 注意你不能跟其他乘客同一时间到达,所以你必须在第二位乘客之前到达。
示例 2:
输入:buses = [20,30,10], passengers = [19,13,26,4,25,11,21], capacity = 2 输出:20 解释: 第 1 辆公交车载着第 4 位乘客。 第 2 辆公交车载着第 6 位和第 2 位乘客。 第 3 辆公交车载着第 1 位乘客和你。

提示:

  • n == buses.length
  • m == passengers.length
  • 1 <= n, m, capacity <= 105
  • 2 <= buses[i], passengers[i] <= 109
  • buses 中的元素 互不相同
  • passengers 中的元素 互不相同

思路:
贪心只要能坐到最后一辆公家车上即可
时间复杂度:O(n)

  1. class Solution {
  2. public int latestTimeCatchTheBus(int[] b, int[] p, int c) {
  3. Arrays.sort(b);
  4. Arrays.sort(p);
  5. Set<Integer> set = new HashSet<>();
  6. for (int x : p)
  7. set.add(x);
  8. int s = 0, last = 0;
  9. for (int i = 0, j = 0; i < b.length; i++) {
  10. s = 0;
  11. while (j < p.length && p[j] <= b[i] && s < c) {
  12. last = p[j];
  13. j++;
  14. s++;
  15. }
  16. }
  17. int x = b[b.length - 1];
  18. if (s == c) x = last;
  19. while (set.contains(x))
  20. x--;
  21. return x;
  22. }
  23. }

6118. 最小差值平方和

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,长度为 n 。
数组 nums1 和 nums2 的 差值平方和 定义为所有满足 0 <= i < n 的 (nums1[i] - nums2[i])2 之和。
同时给你两个正整数 k1 和 k2 。你可以将 nums1 中的任意元素 +1 或者 -1 至多 k1 次。类似的,你可以将 nums2 中的任意元素 +1 或者 -1 至多 k2 次。
请你返回修改数组 _nums1 至多 k1 次且修改数组 nums2 至多 k2 _次后的最小 差值平方和
注意:你可以将数组中的元素变成 整数。

示例 1:
输入:nums1 = [1,2,3,4], nums2 = [2,10,20,19], k1 = 0, k2 = 0 输出:579 解释:nums1 和 nums2 中的元素不能修改,因为 k1 = 0 和 k2 = 0 。 差值平方和为:(1 - 2)2 + (2 - 10)2 + (3 - 20)2 + (4 - 19)2 = 579 。
示例 2:
输入:nums1 = [1,4,10,12], nums2 = [5,8,6,9], k1 = 1, k2 = 1 输出:43 解释:一种得到最小差值平方和的方式为: - 将 nums1[0] 增加一次。 - 将 nums2[2] 增加一次。 最小差值平方和为: (2 - 5)2 + (4 - 8)2 + (10 - 7)2 + (12 - 9)2 = 43 。 注意,也有其他方式可以得到最小差值平方和,但没有得到比 43 更小答案的方案。

提示:

  • n == nums1.length == nums2.length
  • 1 <= n <= 105
  • 0 <= nums1[i], nums2[i] <= 105
  • 0 <= k1, k2 <= 109

思路:
二分 + 贪心
时间复杂度:O(nlogn)

  1. class Solution {
  2. public long minSumSquareDiff(int[] nums1, int[] nums2, int k1, int k2) {
  3. int n = nums1.length;
  4. int[] a = new int[n];
  5. for (int i = 0; i < n; i++) {
  6. a[i] = Math.abs(nums1[i] - nums2[i]);
  7. }
  8. long sum = 1L * k1 + k2;
  9. int l = 0, r = 100000;
  10. while (l < r) {
  11. int mid = l + r >> 1;
  12. long s = get(a, mid);
  13. if (s <= sum)
  14. r = mid;
  15. else
  16. l = mid + 1;
  17. }
  18. if (l == 0) return 0;
  19. long s = get(a, l);
  20. long minus = sum - s;
  21. long res = 0;
  22. for (int x : a) {
  23. if (x < l)
  24. res += 1L * x * x;
  25. else {
  26. if (minus > 0) {
  27. res += 1L * (l - 1) * (l - 1);
  28. minus--;
  29. } else res += 1L * l * l;
  30. }
  31. }
  32. return res;
  33. }
  34. long get(int[] a, int x) {
  35. long res = 0;
  36. for (int v : a) {
  37. if (v > x) res += v - x;
  38. }
  39. return res;
  40. }
  41. }

6119. 元素值大于变化阈值的子数组

给你一个整数数组 nums 和一个整数 threshold 。
找到长度为 k 的 nums 子数组,满足数组中 每个 元素都 大于 threshold / k 。
请你返回满足要求的 任意 子数组的 大小 。如果没有这样的子数组,返回 -1 。
子数组 是数组中一段连续非空的元素序列。

示例 1:
输入:nums = [1,3,4,3,1], threshold = 6 输出:3 解释:子数组 [3,4,3] 大小为 3 ,每个元素都大于 6 / 3 = 2 。 注意这是唯一合法的子数组。
示例 2:
输入:nums = [6,5,6,5,8], threshold = 7 输出:1 解释:子数组 [8] 大小为 1 ,且 8 > 7 / 1 = 7 。所以返回 1 。 注意子数组 [6,5] 大小为 2 ,每个元素都大于 7 / 2 = 3.5 。 类似的,子数组 [6,5,6] ,[6,5,6,5] ,[6,5,6,5,8] 都是符合条件的子数组。 所以返回 2, 3, 4 和 5 都可以。

提示:

  • 1 <= nums.length <= 105
  • 1 <= nums[i], threshold <= 109

思路:
单调栈
时间复杂度:O(n)

  1. class Solution {
  2. public int validSubarraySize(int[] nums, int t) {
  3. int n = nums.length;
  4. for (int i = 0; i < n; i++) {
  5. nums[i] = t / nums[i] + 1;
  6. }
  7. int[] stk = new int[n];
  8. int p = -1;
  9. int[] pre = new int[n], last = new int[n];
  10. for (int i = 0; i < n; i++) {
  11. while (p > -1 && nums[stk[p]] <= nums[i])
  12. p--;
  13. if (p == -1) pre[i] = -1;
  14. else pre[i] = stk[p];
  15. stk[++p] = i;
  16. }
  17. p = -1;
  18. for (int i = n - 1; i >= 0; i--) {
  19. while (p > -1 && nums[stk[p]] <= nums[i])
  20. p--;
  21. if (p == -1) last[i] = n;
  22. else last[i] = stk[p];
  23. stk[++p] = i;
  24. }
  25. for (int i = 0; i < n; i++) {
  26. if (last[i] - pre[i] - 1 >= nums[i])
  27. return nums[i];
  28. }
  29. return -1;
  30. }
  31. }