image.png

t4不会,听说是欧拉回路,得补一下知识点!
t3wrong了一次,因为建图的边没开够空间!

5942. 找出 3 位偶数

给你一个整数数组 digits ,其中每个元素是一个数字(0 - 9)。数组中可能存在重复元素。
你需要找出 所有 满足下述条件且 互不相同 的整数:

  • 该整数由 digits 中的三个元素按 任意 顺序 依次连接 组成。
  • 该整数不含 前导零
  • 该整数是一个 偶数

例如,给定的 digits 是 [1, 2, 3] ,整数 132 和 312 满足上面列出的全部条件。
将找出的所有互不相同的整数按 递增顺序 排列,并以数组形式返回

示例 1:
输入:digits = [2,1,3,0] 输出:[102,120,130,132,210,230,302,310,312,320] 解释: 所有满足题目条件的整数都在输出数组中列出。 注意,答案数组中不含有 奇数 或带 前导零 的整数。
示例 2:
输入:digits = [2,2,8,8,2] 输出:[222,228,282,288,822,828,882] 解释: 同样的数字(0 - 9)在构造整数时可以重复多次,重复次数最多与其在 digits 中出现的次数一样。 在这个例子中,数字 8 在构造 288、828 和 882 时都重复了两次。
示例 3:
输入:digits = [3,7,5] 输出:[] 解释: 使用给定的 digits 无法构造偶数。
示例 4:
输入:digits = [0,2,0,0] 输出:[200] 解释: 唯一一个不含 前导零 且满足全部条件的整数是 200 。
示例 5:
输入:digits = [0,0,0] 输出:[] 解释: 构造的所有整数都会有 前导零 。因此,不存在满足题目条件的整数。

提示:

  • 3 <= digits.length <= 100
  • 0 <= digits[i] <= 9

思路:
暴力三重循环 + Set去重

  1. class Solution {
  2. public int[] findEvenNumbers(int[] d) {
  3. Set<Integer> set = new HashSet<>();
  4. int n = d.length;
  5. for (int i = 0; i < n; i++) {
  6. if (d[i] == 0) continue;
  7. for (int j = 0; j < n; j++) {
  8. if (j == i) continue;
  9. for (int k = 0; k < n; k++) {
  10. if (k == i || k == j || d[k] % 2 != 0)
  11. continue;
  12. set.add(d[i] * 100 + d[j] * 10 + d[k]);
  13. }
  14. }
  15. }
  16. int[] res = new int[set.size()];
  17. int idx = 0;
  18. for (int x : set)
  19. res[idx++] = x;
  20. Arrays.sort(res);
  21. return res;
  22. }
  23. }

5943. 删除链表的中间节点

给你一个链表的头节点 head 。删除 链表的 中间节点 ,并返回修改后的链表的头节点 head 。
长度为 n 链表的中间节点是从头数起第 ⌊n / 2⌋ 个节点(下标从 0 开始),其中 ⌊x⌋ 表示小于或等于 x 的最大整数。

  • 对于 n = 1、2、3、4 和 5 的情况,中间节点的下标分别是 0、1、1、2 和 2 。

示例 1:
image.png
输入:head = [1,3,4,7,1,2,6] 输出:[1,3,4,1,2,6] 解释: 上图表示给出的链表。节点的下标分别标注在每个节点的下方。 由于 n = 7 ,值为 7 的节点 3 是中间节点,用红色标注。 返回结果为移除节点后的新链表。
示例 2:
image.png
输入:head = [1,2,3,4] 输出:[1,2,4] 解释: 上图表示给出的链表。 对于 n = 4 ,值为 3 的节点 2 是中间节点,用红色标注。
示例 3:
image.png
输入:head = [2,1] 输出:[2] 解释: 上图表示给出的链表。 对于 n = 2 ,值为 1 的节点 1 是中间节点,用红色标注。 值为 2 的节点 0 是移除节点 1 后剩下的唯一一个节点。

提示:

  • 链表中节点的数目在范围 [1, 105] 内
  • 1 <= Node.val <= 105

思路:快慢指针

  1. /**
  2. * Definition for singly-linked list.
  3. * public class ListNode {
  4. * int val;
  5. * ListNode next;
  6. * ListNode() {}
  7. * ListNode(int val) { this.val = val; }
  8. * ListNode(int val, ListNode next) { this.val = val; this.next = next; }
  9. * }
  10. */
  11. class Solution {
  12. public ListNode deleteMiddle(ListNode head) {
  13. if (head == null || head.next == null)
  14. return null;
  15. ListNode fast = head, slow = head, pre = null;
  16. do {
  17. pre = slow;
  18. fast = fast.next.next;
  19. slow = slow.next;
  20. } while (fast != null && fast.next != null);
  21. pre.next = pre.next == null ? null : pre.next.next;
  22. return head;
  23. }
  24. }

5944. 从二叉树一个节点到另一个节点每一步的方向

给你一棵 二叉树 的根节点 root ,这棵二叉树总共有 n 个节点。每个节点的值为 1 到 n 中的一个整数,且互不相同。给你一个整数 startValue ,表示起点节点 s 的值,和另一个不同的整数 destValue ,表示终点节点 t 的值。
请找到从节点 s 到节点 t 的 最短路径 ,并以字符串的形式返回每一步的方向。每一步用 大写 字母 ‘L’ ,’R’ 和 ‘U’ 分别表示一种方向:

  • ‘L’ 表示从一个节点前往它的 左孩子 节点。
  • ‘R’ 表示从一个节点前往它的 右孩子 节点。
  • ‘U’ 表示从一个节点前往它的 节点。

请你返回从 s 到 t 最短路径 每一步的方向。

示例 1:
image.png
输入:root = [5,1,2,3,null,6,4], startValue = 3, destValue = 6 输出:“UURL” 解释:最短路径为:3 → 1 → 5 → 2 → 6 。
示例 2:
image.png
输入:root = [2,1], startValue = 2, destValue = 1 输出:“L” 解释:最短路径为:2 → 1 。

提示:

  • 树中节点数目为 n 。
  • 2 <= n <= 105
  • 1 <= Node.val <= n
  • 树中所有节点的值 互不相同
  • 1 <= startValue, destValue <= n
  • startValue != destValue

思路:
方法一:
建图 + bfs + 倒推路径
方法二:
利用最近公共祖先的性质,起点到终点一定经过其最近公共祖先。
找到从根节点分别到起点和终点的路径,去除其公共前缀,将到起点的剩余部分全换成’U’,再连上到终点的剩余部分即可!。

  1. // 方法一:
  2. /**
  3. * Definition for a binary tree node.
  4. * public class TreeNode {
  5. * int val;
  6. * TreeNode left;
  7. * TreeNode right;
  8. * TreeNode() {}
  9. * TreeNode(int val) { this.val = val; }
  10. * TreeNode(int val, TreeNode left, TreeNode right) {
  11. * this.val = val;
  12. * this.left = left;
  13. * this.right = right;
  14. * }
  15. * }
  16. */
  17. class Solution {
  18. int N = 100010;
  19. int[] h = new int[N], e = new int[2 * N], ne = new int[2 * N];
  20. char[] w = new char[2 * N];
  21. int idx;
  22. int[] pre = new int[N];
  23. char[] cp = new char[N];
  24. int S, E;
  25. StringBuilder sb= new StringBuilder();
  26. public String getDirections(TreeNode root, int S, int E) {
  27. this.S = S;
  28. this.E = E;
  29. Arrays.fill(h, -1);
  30. Queue<TreeNode> q = new LinkedList<>();
  31. q.offer(root);
  32. while (!q.isEmpty()) {
  33. TreeNode cur = q.poll();
  34. // n++;
  35. if (cur.left != null) {
  36. q.offer(cur.left);
  37. add(cur.val, cur.left.val, 'L');
  38. add(cur.left.val, cur.val, 'U');
  39. }
  40. if (cur.right != null) {
  41. q.offer(cur.right);
  42. add(cur.val, cur.right.val, 'R');
  43. add(cur.right.val, cur.val, 'U');
  44. }
  45. }
  46. Queue<Integer> q2 = new LinkedList<>();
  47. q2.offer(S);
  48. boolean[] st = new boolean[N];
  49. label: while (!q2.isEmpty()) {
  50. int cur = q2.poll();
  51. st[cur] = true;
  52. for (int i = h[cur]; i != -1; i = ne[i]) {
  53. int j = e[i];
  54. if (st[j]) continue;
  55. q2.offer(j);
  56. pre[j] = cur;
  57. cp[j] = w[i];
  58. if (j == E)
  59. break label;
  60. }
  61. }
  62. // System.out.println(Arrays.toString(pre));
  63. dfs(E);
  64. return sb.reverse().toString();
  65. }
  66. void dfs(int cur) {
  67. if (cur == S) {
  68. return;
  69. }
  70. sb.append(cp[cur]);
  71. dfs(pre[cur]);
  72. }
  73. void add(int a, int b, char c) {
  74. e[idx] = b;
  75. w[idx] = c;
  76. ne[idx] = h[a];
  77. h[a] = idx++;
  78. }
  79. }
  1. // 方法二
  2. /**
  3. * Definition for a binary tree node.
  4. * public class TreeNode {
  5. * int val;
  6. * TreeNode left;
  7. * TreeNode right;
  8. * TreeNode() {}
  9. * TreeNode(int val) { this.val = val; }
  10. * TreeNode(int val, TreeNode left, TreeNode right) {
  11. * this.val = val;
  12. * this.left = left;
  13. * this.right = right;
  14. * }
  15. * }
  16. */
  17. class Solution {
  18. StringBuilder sbs = new StringBuilder();
  19. StringBuilder sbe = new StringBuilder();
  20. public String getDirections(TreeNode root, int startValue, int destValue) {
  21. dfs(root, startValue, true);
  22. dfs(root, destValue, false);
  23. System.out.println(sbs);
  24. System.out.println(sbe);
  25. int j = -1;
  26. for (int i = 0; i < Math.min(sbs.length(), sbe.length()); i++) {
  27. if (sbs.charAt(i) != sbe.charAt(i)) {
  28. j = i;
  29. break;
  30. }
  31. }
  32. if (j == -1)
  33. j = Math.min(sbs.length(), sbe.length());
  34. sbs = new StringBuilder(sbs.substring(j, sbs.length()));
  35. String s = sbe.substring(j, sbe.length());
  36. for (int i = 0; i < sbs.length(); i++)
  37. sbs.setCharAt(i, 'U');
  38. sbs.append(s);
  39. return sbs.toString();
  40. }
  41. boolean dfs(TreeNode root , int x, boolean flag) {
  42. StringBuilder sb = flag ? sbs : sbe;
  43. if (root == null) return false;
  44. if (root.val == x) return true;
  45. sb.append('L');
  46. if (dfs(root.left, x, flag))
  47. return true;
  48. sb.deleteCharAt(sb.length() - 1);
  49. sb.append('R');
  50. if (dfs(root.right, x, flag))
  51. return true;
  52. sb.deleteCharAt(sb.length() - 1);
  53. return false;
  54. }
  55. }

5932. 合法重新排列数对

给你一个下标从 0 开始的二维整数数组 pairs ,其中 pairs[i] = [starti, endi] 。如果 pairs 的一个重新排列,满足对每一个下标 i ( 1 <= i < pairs.length )都有 endi-1 == starti ,那么我们就认为这个重新排列是 pairs 的一个 合法重新排列
请你返回 任意一个 pairs 的合法重新排列。
注意:数据保证至少存在一个 pairs 的合法重新排列。

示例 1:
输入:pairs = [[5,1],[4,5],[11,9],[9,4]] 输出:[[11,9],[9,4],[4,5],[5,1]] 解释: 输出的是一个合法重新排列,因为每一个 endi-1 都等于 starti 。 end0 = 9 == 9 = start1 end1 = 4 == 4 = start2 end2 = 5 == 5 = start3
示例 2:
输入:pairs = [[1,3],[3,2],[2,1]] 输出:[[1,3],[3,2],[2,1]] 解释: 输出的是一个合法重新排列,因为每一个 endi-1 都等于 starti 。 end0 = 3 == 3 = start1 end1 = 2 == 2 = start2 重新排列后的数组 [[2,1],[1,3],[3,2]] 和 [[3,2],[2,1],[1,3]] 都是合法的。
示例 3:
输入:pairs = [[1,2],[1,3],[2,1]] 输出:[[1,2],[2,1],[1,3]] 解释: 输出的是一个合法重新排列,因为每一个 endi-1 都等于 starti 。 end0 = 2 == 2 = start1 end1 = 1 == 1 = start2

提示:

  • 1 <= pairs.length <= 105
  • pairs[i].length == 2
  • 0 <= starti, endi <= 109
  • starti != endi
  • pairs 中不存在一模一样的数对。
  • 至少 存在 一个合法的pairs 重新排列。

思路:
欧拉通路,本题给定了条件,一定存在欧拉通路。
如果没有给定,如何判断呢?
如果是无向图,欧拉通路需满足奇度节点的个数为0或2,其余均为偶度节点
如果是无向图,欧拉通路需满足,所有点的入度等于出度,或者有且只有一点出度比入度大1,有且只有一点入度比出度大1,其余节点入度与出度均相等。
另一个问题是如何求解欧拉通路,即如何求出一笔画的路线呢?
用递归,从起点出发,一条道走到黑再向回倒退,一旦能向前走则继续一条道走到黑,直至遍历完所有的边

  1. class Solution {
  2. Map<Integer, Queue<Integer>> map = new HashMap<>();
  3. List<int[]> t = new ArrayList<>();
  4. public int[][] validArrangement(int[][] pairs) {
  5. for (int[] p : pairs) {
  6. int a = p[0], b = p[1];
  7. map.computeIfAbsent(a, key -> new LinkedList<>()).offer(b);
  8. }
  9. Map<Integer, Integer> in = new HashMap<>();
  10. Map<Integer, Integer> out = new HashMap<>();
  11. for (Integer key : map.keySet()) {
  12. Queue<Integer> list = map.get(key);
  13. out.merge(key, list.size(), Integer::sum);
  14. for (int x : list) {
  15. in.merge(x, 1, Integer::sum);
  16. }
  17. }
  18. int start = -1;
  19. for (int key : out.keySet()) {
  20. int din = in.getOrDefault(key, 0);
  21. int dout = out.get(key);
  22. if (din + 1 == dout) {
  23. start = key;
  24. break;
  25. }
  26. }
  27. if (start == -1) {
  28. start = pairs[0][0];
  29. }
  30. dfs(start);
  31. int[][] res = new int[t.size()][2];
  32. for (int i = 0, j = t.size() - 1; j >= 0; i++, j--) {
  33. res[i] = t.get(j);
  34. }
  35. return res;
  36. }
  37. //欧拉通路的精髓
  38. void dfs(int u) {
  39. Queue<Integer> q = map.get(u);
  40. if (q == null) return;
  41. while (!q.isEmpty()) {
  42. int v = q.poll();
  43. dfs(v);
  44. t.add(new int[]{u, v});
  45. }
  46. }
  47. }