image.png
第一题没看懂题,差点放弃,还好坚持了一下,t2和t3都是DP,最近的DP真多啊。

6101. 判断矩阵是否是一个 X 矩阵

image.pngimage.png
如果一个正方形矩阵满足下述 全部 条件,则称之为一个 X 矩阵

  1. 矩阵对角线上的所有元素都 不是 0
  2. 矩阵中所有其他元素都是 0

给你一个大小为 n x n 的二维整数数组 grid ,表示一个正方形矩阵。如果 _grid _是一个 X 矩阵 ,返回 true ;否则,返回 false 。

示例 1:
输入:grid = [[2,0,0,1],[0,3,1,0],[0,5,2,0],[4,0,0,2]] 输出:true 解释:矩阵如上图所示。 X 矩阵应该满足:绿色元素(对角线上)都不是 0 ,红色元素都是 0 。 因此,grid 是一个 X 矩阵。
示例 2:
输入:grid = [[5,7,0],[0,3,1],[0,5,0]] 输出:false 解释:矩阵如上图所示。 X 矩阵应该满足:绿色元素(对角线上)都不是 0 ,红色元素都是 0 。 因此,grid 不是一个 X 矩阵。

提示:

  • n == grid.length == grid[i].length
  • 3 <= n <= 100
  • 0 <= grid[i][j] <= 105

思路:
判断每一个数即可

  1. class Solution {
  2. public boolean checkXMatrix(int[][] g) {
  3. int n = g.length;
  4. for (int i = 0; i < n; i++) {
  5. for (int j = 0; j < n; j++) {
  6. if (i == j || i + j == n - 1) {
  7. if (g[i][j] == 0) return false;
  8. } else {
  9. if (g[i][j] != 0) return false;
  10. }
  11. }
  12. }
  13. return true;
  14. }
  15. }

6100. 统计放置房子的方式数

image.png
一条街道上共有 n 2 个 *地块 ,街道的两侧各有 n 个地块。每一边的地块都按从 1 到 n 编号。每个地块上都可以放置一所房子。
现要求街道同一侧不能存在两所房子相邻的情况,请你计算并返回放置房屋的方式数目。由于答案可能很大,需要对 109 + 7 取余后再返回。
注意,如果一所房子放置在这条街某一侧上的第 i 个地块,不影响在另一侧的第 i 个地块放置房子。

示例 1:
输入:n = 1 输出:4 解释: 可能的放置方式: 1. 所有地块都不放置房子。 2. 一所房子放在街道的某一侧。 3. 一所房子放在街道的另一侧。 4. 放置两所房子,街道两侧各放置一所。
示例 2:
输入:n = 2 输出:9 解释:如上图所示,共有 9 种可能的放置方式。

提示:

  • 1 <= n <= 104

思路:
状态机DP

  1. class Solution {
  2. public int countHousePlacements(int n) {
  3. int MOD = (int)(1e9 + 7);
  4. int[][] f = new int[n + 1][4];
  5. for (int i = 0; i < 4; i++)
  6. f[1][i] = 1;
  7. for (int i = 2; i <= n; i++) {
  8. for (int j = 0; j < 4; j++) {
  9. for (int k = 0; k < 4; k++) {
  10. if ((j & k) == 0) {
  11. f[i][j] = (f[i][j] + f[i - 1][k]) % MOD;
  12. }
  13. }
  14. }
  15. }
  16. int sum = 0;
  17. for (int i = 0; i < 4; i++)
  18. sum = (sum + f[n][i]) % MOD;
  19. return sum;
  20. }
  21. }

5229. 拼接数组的最大分数

给你两个下标从 0 开始的整数数组 nums1 和 nums2 ,长度都是 n 。
你可以选择两个整数 left 和 right ,其中 0 <= left <= right < n ,接着 交换 两个子数组 nums1[left…right] 和 nums2[left…right] 。

  • 例如,设 nums1 = [1,2,3,4,5] 和 nums2 = [11,12,13,14,15] ,整数选择 left = 1 和 right = 2,那么 nums1 会变为 [1,12,13,4,5] 而 nums2 会变为 [11,2,3,14,15] 。

你可以选择执行上述操作 一次 或不执行任何操作。
数组的 分数 取 sum(nums1) 和 sum(nums2) 中的最大值,其中 sum(arr) 是数组 arr 中所有元素之和。
返回 可能的最大分数
子数组 是数组中连续的一个元素序列。arr[left…right] 表示子数组包含 nums 中下标 left 和 right 之间的元素(含 下标 left 和 right 对应元素

示例 1:
输入:nums1 = [60,60,60], nums2 = [10,90,10] 输出:210 解释:选择 left = 1 和 right = 1 ,得到 nums1 = [60,90,60] 和 nums2 = [10,60,10] 。 分数为 max(sum(nums1), sum(nums2)) = max(210, 80) = 210 。
示例 2:
输入:nums1 = [20,40,20,70,30], nums2 = [50,20,50,40,20] 输出:220 解释:选择 left = 3 和 right = 4 ,得到 nums1 = [20,40,20,40,20] 和 nums2 = [50,20,50,70,30] 。 分数为 max(sum(nums1), sum(nums2)) = max(140, 220) = 220 。
示例 3:
输入:nums1 = [7,11,13], nums2 = [1,1,1] 输出:31 解释:选择不交换任何子数组。 分数为 max(sum(nums1), sum(nums2)) = max(31, 3) = 31 。

提示:

  • n == nums1.length == nums2.length
  • 1 <= n <= 105
  • 1 <= nums1[i], nums2[i] <= 104

思路:
转换成最大连续子序列问题

  1. class Solution {
  2. public int maximumsSplicedArray(int[] nums1, int[] nums2) {
  3. return Math.max(deal(nums1, nums2), deal(nums2, nums1));
  4. }
  5. int deal(int[] a, int [] b) {
  6. int n = a.length;
  7. int[] d = new int[n];
  8. int sum = Arrays.stream(a).sum();
  9. for (int i = 0; i < n; i++) {
  10. d[i] = b[i] - a[i];
  11. }
  12. int max = 0, c = 0;
  13. for (int i = 0; i < n; i++) {
  14. c += d[i];
  15. if (c < 0) c = 0;
  16. max = Math.max(max, c);
  17. }
  18. return max + sum;
  19. }
  20. }

6103. 从树中删除边的最小分数

image.pngimage.png
存在一棵无向连通树,树中有编号从 0 到 n - 1 的 n 个节点, 以及 n - 1 条边。
给你一个下标从 0 开始的整数数组 nums ,长度为 n ,其中 nums[i] 表示第 i 个节点的值。另给你一个二维整数数组 edges ,长度为 n - 1 ,其中 edges[i] = [ai, bi] 表示树中存在一条位于节点 ai 和 bi 之间的边。
删除树中两条 不同 的边以形成三个连通组件。对于一种删除边方案,定义如下步骤以计算其分数:

  1. 分别获取三个组件 每个 组件中所有节点值的异或值。
  2. 最大 异或值和 最小 异或值的 差值 就是这一种删除边方案的分数。
  • 例如,三个组件的节点值分别是:[4,5,7]、[1,9] 和 [3,3,3] 。三个异或值分别是 4 ^ 5 ^ 7 = 6、1 ^ 9 = 8 和 3 ^ 3 ^ 3 = 3 。最大异或值是 8 ,最小异或值是 3 ,分数是 8 - 3 = 5 。

返回在给定树上执行任意删除边方案可能的 最小 分数。

示例 1:
输入:nums = [1,5,5,4,11], edges = [[0,1],[1,2],[1,3],[3,4]] 输出:9 解释:上图展示了一种删除边方案。 - 第 1 个组件的节点是 [1,3,4] ,值是 [5,4,11] 。异或值是 5 ^ 4 ^ 11 = 10 。 - 第 2 个组件的节点是 [0] ,值是 [1] 。异或值是 1 = 1 。 - 第 3 个组件的节点是 [2] ,值是 [5] 。异或值是 5 = 5 。 分数是最大异或值和最小异或值的差值,10 - 1 = 9 。 可以证明不存在分数比 9 小的删除边方案。
示例 2:
输入:nums = [5,5,2,4,4,2], edges = [[0,1],[1,2],[5,2],[4,3],[1,3]] 输出:0 解释:上图展示了一种删除边方案。 - 第 1 个组件的节点是 [3,4] ,值是 [4,4] 。异或值是 4 ^ 4 = 0 。 - 第 2 个组件的节点是 [1,0] ,值是 [5,5] 。异或值是 5 ^ 5 = 0 。 - 第 3 个组件的节点是 [2,5] ,值是 [2,2] 。异或值是 2 ^ 2 = 0 。 分数是最大异或值和最小异或值的差值,0 - 0 = 0 。 无法获得比 0 更小的分数 0 。

提示:

  • n == nums.length
  • 3 <= n <= 1000
  • 1 <= nums[i] <= 108
  • edges.length == n - 1
  • edges[i].length == 2
  • 0 <= ai, bi < n
  • ai != bi
  • edges 表示一棵有效的树

思路:
范围只有1000考虑O(n2)的做法。
分类讨论即可

  1. class Solution {
  2. int N = 1010;
  3. int[] h = new int[N], e = new int[2 * N], ne = new int[2 * N];
  4. int idx = 0;
  5. int[] w = new int[N];
  6. int n;
  7. int[] nums;
  8. Set<Integer>[] set = new HashSet[N];
  9. public int minimumScore(int[] nums, int[][] edges) {
  10. this.nums = nums;
  11. Arrays.fill(h, -1);
  12. n = nums.length;
  13. for (int[] p : edges) {
  14. int a = p[0], b = p[1];
  15. add(a, b);
  16. add(b, a);
  17. }
  18. dfs(0, -1);
  19. dfs2(0, -1);
  20. int res = 0x3f3f3f3f;
  21. for (int i = 1; i < n; i++) {
  22. for (int j = 1; j < n; j++) {
  23. if (i == j) continue;
  24. int a = 0, b = 0, c = 0;
  25. if (set[i].contains(j)) {
  26. a = w[i] ^ w[j];
  27. b = w[j];
  28. c = w[0] ^ w[i];
  29. } else if (set[j].contains(i)) {
  30. a = w[j] ^ w[i];
  31. b = w[i];
  32. c = w[0] ^ w[j];
  33. } else {
  34. a = w[i];
  35. b = w[j];
  36. c = w[0] ^ w[i] ^ w[j];
  37. }
  38. int max = Math.max(a, Math.max(b, c)), min = Math.min(a, Math.min(b, c));
  39. res = Math.min(max - min, res);
  40. }
  41. }
  42. return res;
  43. }
  44. Set<Integer> dfs2(int u, int pre) {
  45. Set<Integer> res = new HashSet<>();
  46. res.add(u);
  47. for (int i = h[u]; i != -1; i = ne[i]) {
  48. int j = e[i];
  49. if (j == pre) continue;
  50. res.addAll(dfs2(j, u));
  51. }
  52. set[u] = new HashSet<>(res);
  53. return res;
  54. }
  55. int dfs(int u, int pre) {
  56. int res = nums[u];
  57. for (int i = h[u]; i != -1; i = ne[i]) {
  58. int j = e[i];
  59. if (j == pre) continue;
  60. res ^= dfs(j, u);
  61. }
  62. w[u] = res;
  63. return res;
  64. }
  65. void add(int a, int b) {
  66. e[idx] = b;
  67. ne[idx] = h[a];
  68. h[a] = idx++;
  69. }
  70. }