image.png
最后一题急了,冷静下来想想其实没那么麻烦

6132. 使数组中所有元素都等于零

给你一个非负整数数组 nums 。在一步操作中,你必须:

  • 选出一个正整数 x ,x 需要小于或等于 nums 中 最小非零 元素。
  • nums 中的每个正整数都减去 x。

返回使 nums 中所有元素都等于_ _0 需要的 最少 操作数。

示例 1:
输入:nums = [1,5,0,3,5] 输出:3 解释: 第一步操作:选出 x = 1 ,之后 nums = [0,4,0,2,4] 。 第二步操作:选出 x = 2 ,之后 nums = [0,2,0,0,2] 。 第三步操作:选出 x = 2 ,之后 nums = [0,0,0,0,0] 。
示例 2:
输入:nums = [0] 输出:0 解释:nums 中的每个元素都已经是 0 ,所以不需要执行任何操作。

提示:

  • 1 <= nums.length <= 100
  • 0 <= nums[i] <= 100

思路:
找除0外不同数的个数

  1. class Solution {
  2. public int minimumOperations(int[] nums) {
  3. // Arrays.sort(nums);
  4. Set<Integer> set = new HashSet<>();
  5. for (int x : nums) {
  6. if (x == 0) continue;
  7. set.add(x);
  8. }
  9. return set.size();
  10. }
  11. }

6133. 分组的最大数量

给你一个正整数数组 grades ,表示大学中一些学生的成绩。你打算将 所有 学生分为一些 有序 的非空分组,其中分组间的顺序满足以下全部条件:

  • 第 i 个分组中的学生总成绩 小于 第 (i + 1) 个分组中的学生总成绩,对所有组均成立(除了最后一组)。
  • 第 i 个分组中的学生总数 小于 第 (i + 1) 个分组中的学生总数,对所有组均成立(除了最后一组)。

返回可以形成的 最大 组数。

示例 1:
输入:grades = [10,6,12,7,3,5] 输出:3 解释:下面是形成 3 个分组的一种可行方法: - 第 1 个分组的学生成绩为 grades = [12] ,总成绩:12 ,学生数:1 - 第 2 个分组的学生成绩为 grades = [6,7] ,总成绩:6 + 7 = 13 ,学生数:2 - 第 3 个分组的学生成绩为 grades = [10,3,5] ,总成绩:10 + 3 + 5 = 18 ,学生数:3 可以证明无法形成超过 3 个分组。
示例 2:
输入:grades = [8,8] 输出:1 解释:只能形成 1 个分组,因为如果要形成 2 个分组的话,会导致每个分组中的学生数目相等。

提示:

  • 1 <= grades.length <= 105
  • 1 <= grades[i] <= 105

思路:
贪心,排序后从小到大,每组人数递增

  1. class Solution {
  2. public int maximumGroups(int[] grades) {
  3. Arrays.sort(grades);
  4. int c = 1, s = 0;
  5. while (s + c <= grades.length) {
  6. s += c;
  7. c++;
  8. }
  9. return c - 1;
  10. }
  11. }

6134. 找到离给定两个节点最近的节点

显示英文描述
我的提交返回竞赛

  • 通过的用户数2835
  • 尝试过的用户数4068
  • 用户总通过次数2935
  • 用户总提交次数12895
  • 题目难度Medium

给你一个 n 个节点的 有向图 ,节点编号为 0 到 n - 1 ,每个节点 至多 有一条出边。
有向图用大小为 n 下标从 0 开始的数组 edges 表示,表示节点 i 有一条有向边指向 edges[i] 。如果节点 i 没有出边,那么 edges[i] == -1 。
同时给你两个节点 node1 和 node2 。
请你返回一个从 node1 和 node2 都能到达节点的编号,使节点 node1 和节点 node2 到这个节点的距离 较大值最小化。如果有多个答案,请返回 最小 的节点编号。如果答案不存在,返回 -1 。
注意 edges 可能包含环。

示例 1:
image.png
输入:edges = [2,2,3,-1], node1 = 0, node2 = 1 输出:2 解释:从节点 0 到节点 2 的距离为 1 ,从节点 1 到节点 2 的距离为 1 。 两个距离的较大值为 1 。我们无法得到一个比 1 更小的较大值,所以我们返回节点 2 。
示例 2:
image.png
输入:edges = [1,2,-1], node1 = 0, node2 = 2 输出:2 解释:节点 0 到节点 2 的距离为 2 ,节点 2 到它自己的距离为 0 。 两个距离的较大值为 2 。我们无法得到一个比 2 更小的较大值,所以我们返回节点 2 。

提示:

  • n == edges.length
  • 2 <= n <= 105
  • -1 <= edges[i] < n
  • edges[i] != i
  • 0 <= node1, node2 < n

思路:
比赛的时候用的bfs求两次最短路
其实每个点到其余所有点的路径都是唯一的,直接对着原数组遍历求就行

  1. // 赛时代码
  2. class Solution {
  3. int N = 100010;
  4. int[] h = new int[N], e = new int[N], ne = new int[N];
  5. int[] d1 = new int[N], d2 = new int[N];
  6. int idx, n;
  7. public int closestMeetingNode(int[] edges, int node1, int node2) {
  8. n = edges.length;
  9. Arrays.fill(h, -1);
  10. for (int i = 0; i < n; i++) {
  11. if (edges[i] == -1) continue;
  12. add(i, edges[i]);
  13. }
  14. dijk(node1, d1);
  15. dijk(node2, d2);
  16. int max = 0x3f3f3f3f, node = n;
  17. for (int i = 0; i < n; i++) {
  18. if (d1[i] == 0x3f3f3f3f || d2[i] == 0x3f3f3f3f)
  19. continue;
  20. int v = Math.max(d1[i], d2[i]);
  21. if (v < max) {
  22. max = v;
  23. node = i;
  24. }
  25. }
  26. return max == 0x3f3f3f3f ? -1 : node;
  27. }
  28. void dijk(int s, int[] d) {
  29. Arrays.fill(d, 0x3f3f3f3f);
  30. Queue<Integer> q = new LinkedList<>();
  31. q.offer(s);
  32. d[s] = 0;
  33. int cnt = 0;
  34. while (!q.isEmpty()) {
  35. cnt++;
  36. int size = q.size();
  37. while (size-- > 0) {
  38. int u = q.poll();
  39. for (int i = h[u]; i != -1; i = ne[i]) {
  40. int j = e[i];
  41. if (d[j] > cnt) {
  42. d[j] = cnt;
  43. q.offer(j);
  44. }
  45. }
  46. }
  47. }
  48. }
  49. void add(int a, int b) {
  50. e[idx] = b;
  51. ne[idx] = h[a];
  52. h[a] = idx++;
  53. }
  54. }
  1. class Solution {
  2. public int closestMeetingNode(int[] e, int node1, int node2) {
  3. int n = e.length;
  4. int[] d1 = new int[n], d2 = new int[n];
  5. Arrays.fill(d1, 0x3f3f3f3f);
  6. Arrays.fill(d2, 0x3f3f3f3f);
  7. d1[node1] = 0;
  8. for (int i = node1; i >= 0; i = e[i]) {
  9. int j = e[i];
  10. if (j == -1) break;
  11. if (d1[j] != 0x3f3f3f3f) break;
  12. d1[j] = d1[i] + 1;
  13. }
  14. d2[node2] = 0;
  15. for (int i = node2; i >= 0; i = e[i]) {
  16. int j = e[i];
  17. if (j == -1) break;
  18. if (d2[j] != 0x3f3f3f3f) break;
  19. d2[j] = d2[i] + 1;
  20. }
  21. int max = 0x3f3f3f3f, node = -1;
  22. for (int i = 0; i < n; i++) {
  23. int v = Math.max(d1[i], d2[i]);
  24. if (v < max) {
  25. max = v;
  26. node = i;
  27. }
  28. }
  29. return node;
  30. }
  31. }

6135. 图中的最长环

给你一个 n 个节点的 有向图 ,节点编号为 0 到 n - 1 ,其中每个节点 至多 有一条出边。
图用一个大小为 n 下标从 0 开始的数组 edges 表示,节点 i 到节点 edges[i] 之间有一条有向边。如果节点 i 没有出边,那么 edges[i] == -1 。
请你返回图中的 最长 环,如果没有任何环,请返回 -1 。
一个环指的是起点和终点是 同一个 节点的路径。

示例 1:
image.png
输入:edges = [3,3,4,2,3] 输出去:3 解释:图中的最长环是:2 -> 4 -> 3 -> 2 。 这个环的长度为 3 ,所以返回 3 。
示例 2:
image.png
输入:edges = [2,-1,3,1] 输出:-1 解释:图中没有任何环。

提示:

  • n == edges.length
  • 2 <= n <= 105
  • -1 <= edges[i] < n
  • edges[i] != i

思路:
遍历找环 + 时间计数器

  1. class Solution {
  2. public int longestCycle(int[] e) {
  3. int n = e.length;
  4. int[] time = new int[n];
  5. int p = 1;
  6. int max = -1;
  7. for (int i = 0; i < n; i++) {
  8. if (time[i] > 0) continue;
  9. int j = i, start = p;
  10. while (j != -1 && time[j] == 0) {
  11. time[j] = p++;
  12. j = e[j];
  13. }
  14. if (j != -1 && time[j] >= start)
  15. max = Math.max(max, p - time[j]);
  16. }
  17. return max;
  18. }
  19. }
  20. // 优化空间写法
  21. class Solution {
  22. public int longestCycle(int[] e) {
  23. int p = 100000, base = 0xfffff;
  24. int max = -1;
  25. for (int i = 0; i < e.length; i++) {
  26. int j = i, c = 0;
  27. while (e[j] >= 0 && e[j] < e.length) {
  28. c++;
  29. int t = e[j];
  30. e[j] = hash(p, c);
  31. j = t;
  32. }
  33. if ((e[j] & base) == p) max = Math.max(max, c - (e[j] >> 20) + 1);
  34. p++;
  35. }
  36. return max;
  37. }
  38. int hash(int p, int c) {
  39. return (c << 20) + p;
  40. }
  41. }