Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 3b6b5c6

Browse files
committed
第450场周赛T1~T4 (4)
1 parent 59c21fe commit 3b6b5c6

File tree

8 files changed

+408
-0
lines changed

8 files changed

+408
-0
lines changed
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
public class Solution3550 {
2+
public int smallestIndex(int[] nums) {
3+
int n = nums.length;
4+
for (int i = 0; i < n; i++) {
5+
if (digitSum(nums[i]) == i) {
6+
return i;
7+
}
8+
}
9+
return -1;
10+
}
11+
12+
private int digitSum(int x) {
13+
int sum = 0;
14+
while (x > 0) {
15+
sum += x % 10;
16+
x /= 10;
17+
}
18+
return sum;
19+
}
20+
}
21+
/*
22+
3550. 数位和等于下标的最小下标
23+
https://leetcode.cn/problems/smallest-index-with-digit-sum-equal-to-index/description/
24+
25+
第 450 场周赛 T1。
26+
27+
给你一个整数数组 nums 。
28+
返回满足 nums[i] 的数位和(每一位数字相加求和)等于 i 的 最小 下标 i 。
29+
如果不存在满足要求的下标,返回 -1 。
30+
提示:
31+
1 <= nums.length <= 100
32+
0 <= nums[i] <= 1000
33+
34+
模拟 遍历。
35+
*/
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import java.util.Arrays;
2+
import java.util.Comparator;
3+
4+
public class Solution3551 {
5+
public int minSwaps(int[] nums) {
6+
int n = nums.length;
7+
int[] b = new int[n]; // 数位和
8+
for (int i = 0; i < n; i++) {
9+
b[i] = digitSum(nums[i]);
10+
}
11+
12+
// 置换环:对于每个环,交换次数为环的大小减一。
13+
Integer[] ids = new Integer[n]; // 将 a 离散化
14+
for (int i = 0; i < n; i++) ids[i] = i;
15+
// 如果两个数字的数位和相等,则较小的数字排在前面。
16+
Arrays.sort(ids, Comparator.comparingInt(o -> b[(int) o])
17+
.thenComparingInt(o -> nums[(int) o]));
18+
19+
int ans = n;
20+
boolean[] vis = new boolean[n];
21+
for (Integer v : ids) {
22+
if (vis[v]) continue;
23+
while (!vis[v]) {
24+
vis[v] = true;
25+
v = ids[v];
26+
}
27+
ans -= 1;
28+
}
29+
return ans;
30+
}
31+
32+
private int digitSum(int x) {
33+
int sum = 0;
34+
while (x > 0) {
35+
sum += x % 10;
36+
x /= 10;
37+
}
38+
return sum;
39+
}
40+
}
41+
/*
42+
3551. 数位和排序需要的最小交换次数
43+
https://leetcode.cn/problems/minimum-swaps-to-sort-by-digit-sum/description/
44+
45+
第 450 场周赛 T2。
46+
47+
给你一个由 互不相同 的正整数组成的数组 nums,需要根据每个数字的数位和(即每一位数字相加求和)按 升序 对数组进行排序。如果两个数字的数位和相等,则较小的数字排在前面。
48+
返回将 nums 排列为上述排序顺序所需的 最小 交换次数。
49+
一次 交换 定义为交换数组中两个不同位置的值。
50+
提示:
51+
1 <= nums.length <= 10^5
52+
1 <= nums[i] <= 10^9
53+
nums 由 互不相同 的正整数组成。
54+
55+
置换环。
56+
相似题目: 2471. 逐层排序二叉树所需的最少操作数目
57+
https://leetcode.cn/problems/minimum-number-of-operations-to-sort-a-binary-tree-by-level/
58+
*/
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
import java.util.ArrayDeque;
2+
import java.util.ArrayList;
3+
import java.util.Arrays;
4+
import java.util.Deque;
5+
import java.util.List;
6+
7+
public class Solution3552 {
8+
private static final int[][] DIRECTIONS = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
9+
private int[] dist;
10+
private Deque<int[]> dq;
11+
12+
public int minMoves(String[] matrix) {
13+
int m = matrix.length;
14+
int n = matrix[0].length();
15+
16+
List<Integer>[] trans = new ArrayList[26];
17+
Arrays.setAll(trans, e -> new ArrayList<>());
18+
for (int i = 0; i < m; i++) {
19+
for (int j = 0; j < n; j++) {
20+
char c = matrix[i].charAt(j);
21+
if ('A' <= c && c <= 'Z') {
22+
trans[c - 'A'].add(i * n + j);
23+
}
24+
}
25+
}
26+
27+
// 节点编号:格子从 0 到 nm - 1,传送中心从 nm 到 nm + 25
28+
dist = new int[n * m + 26];
29+
Arrays.fill(dist, -1);
30+
dq = new ArrayDeque<>(); // dis, sn
31+
dq.add(new int[]{0, 0});
32+
33+
while (!dq.isEmpty()) {
34+
int[] p = dq.removeFirst();
35+
int dis = p[0], sn = p[1];
36+
if (dist[sn] >= 0) continue;
37+
dist[sn] = dis;
38+
39+
if (sn < m * n) {
40+
// 在格子上
41+
int cx = sn / n;
42+
int cy = sn % n;
43+
for (int[] d : DIRECTIONS) {
44+
int nx = cx + d[0];
45+
int ny = cy + d[1];
46+
if (nx >= 0 && nx < m && ny >= 0 && ny < n && matrix[nx].charAt(ny) != '#') {
47+
addDeque(sn, nx * n + ny, 1);
48+
}
49+
}
50+
// 如果格子上有字母,还可以走到传送中心
51+
char c = matrix[cx].charAt(cy);
52+
if ('A' <= c && c <= 'Z') {
53+
addDeque(sn, n * m + (c - 'A'), 0);
54+
}
55+
} else {
56+
// 在传送中心里
57+
for (int next_sn : trans[sn - n * m]) {
58+
addDeque(sn, next_sn, 0);
59+
}
60+
}
61+
}
62+
return dist[n * m - 1];
63+
}
64+
65+
// val:增量 0/1
66+
private void addDeque(int sn, int next_sn, int val) {
67+
if (dist[next_sn] >= 0) return;
68+
if (val == 0) dq.addFirst(new int[]{dist[sn], next_sn});
69+
else dq.addLast(new int[]{dist[sn] + 1, next_sn});
70+
}
71+
}
72+
/*
73+
3552. 网格传送门旅游
74+
https://leetcode.cn/problems/grid-teleportation-traversal/description/
75+
76+
第 450 场周赛 T3。
77+
78+
给你一个大小为 m x n 的二维字符网格 matrix,用字符串数组表示,其中 matrix[i][j] 表示第 i 行和第 j 列处的单元格。每个单元格可以是以下几种字符之一:
79+
- '.' 表示一个空单元格。
80+
- '#' 表示一个障碍物。
81+
- 一个大写字母('A' 到 'Z')表示一个传送门。
82+
你从左上角单元格 (0, 0) 出发,目标是到达右下角单元格 (m - 1, n - 1)。你可以从当前位置移动到相邻的单元格(上、下、左、右),移动后的单元格必须在网格边界内且不是障碍物。
83+
如果你踏入一个包含传送门字母的单元格,并且你之前没有使用过该传送门字母,你可以立即传送到网格中另一个具有相同字母的单元格。这次传送不计入移动次数,但每个字母对应的传送门在旅程中 最多 只能使用一次。
84+
返回到达右下角单元格所需的 最少 移动次数。如果无法到达目的地,则返回 -1。
85+
提示:
86+
1 <= m == matrix.length <= 10^3
87+
1 <= n == matrix[i].length <= 10^3
88+
matrix[i][j] 是 '#'、'.' 或一个大写英文字母。
89+
matrix[0][0] 不是障碍物。
90+
91+
0-1 BFS。
92+
时间复杂度 O(mn)。
93+
rating 2009 (clist.by)
94+
*/
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.List;
4+
5+
public class Solution3553 {
6+
private List<int[]>[] g;
7+
private int dfn;
8+
private int[][] nodes; // l, r
9+
private final int mx = 17;
10+
private int[][] pa;
11+
private int[] dep;
12+
private int[] sum_to_root;
13+
14+
public int[] minimumWeight(int[][] edges, int[][] queries) {
15+
int n = edges.length + 1;
16+
g = new ArrayList[n];
17+
Arrays.setAll(g, e -> new ArrayList<>());
18+
for (int[] e : edges) {
19+
g[e[0]].add(new int[]{e[1], e[2]});
20+
g[e[1]].add(new int[]{e[0], e[2]});
21+
}
22+
dfn = 0;
23+
nodes = new int[n][2];
24+
pa = new int[n][mx];
25+
dep = new int[n];
26+
sum_to_root = new int[n];
27+
build(0, -1);
28+
for (int i = 0; i + 1 < mx; i++) {
29+
for (int v = 0; v < pa.length; v++) {
30+
int p = pa[v][i];
31+
if (p != -1) {
32+
pa[v][i + 1] = pa[p][i];
33+
} else {
34+
pa[v][i + 1] = -1;
35+
}
36+
}
37+
}
38+
39+
int[] ans = new int[queries.length];
40+
for (int i = 0; i < queries.length; i++) {
41+
int src1 = queries[i][0], src2 = queries[i][1], dest = queries[i][2];
42+
int sum1 = get_path_sum(src1, dest);
43+
int sum2 = get_path_sum(src2, dest);
44+
int sum3 = get_path_sum(src1, src2);
45+
ans[i] = (sum1 + sum2 + sum3) / 2;
46+
}
47+
return ans;
48+
}
49+
50+
int get_path_sum(int u, int v) {
51+
int ancestor = getLCA(u, v);
52+
return sum_to_root[u] + sum_to_root[v] - 2 * sum_to_root[ancestor];
53+
}
54+
55+
int build(int v, int fa) {
56+
dfn++;
57+
nodes[v][0] = dfn;
58+
pa[v][0] = fa;
59+
int sz = 1;
60+
for (int[] p : g[v]) {
61+
int w = p[0], wt = p[1];
62+
if (w != fa) {
63+
dep[w] = dep[v] + 1;
64+
sum_to_root[w] = sum_to_root[v] + wt;
65+
sz += build(w, v);
66+
}
67+
}
68+
nodes[v][1] = nodes[v][0] + sz - 1;
69+
return sz;
70+
}
71+
72+
int uptoDep(int v, int d) {
73+
for (int k = dep[v] - d; k > 0; k &= k - 1) {
74+
v = pa[v][Integer.numberOfTrailingZeros(k)];
75+
}
76+
return v;
77+
}
78+
79+
int getLCA(int v, int w) {
80+
if (dep[v] > dep[w]) {
81+
int tmp = v;
82+
v = w;
83+
w = tmp;
84+
}
85+
w = uptoDep(w, dep[v]);
86+
if (w == v) return v;
87+
for (int i = mx - 1; i >= 0; i--) {
88+
if (pa[v][i] != pa[w][i]) {
89+
v = pa[v][i];
90+
w = pa[w][i];
91+
}
92+
}
93+
return pa[v][0];
94+
}
95+
}
96+
/*
97+
3553. 包含给定路径的最小带权子树 II
98+
https://leetcode.cn/problems/minimum-weighted-subgraph-with-the-required-paths-ii/description/
99+
100+
第 450 场周赛 T4。
101+
102+
给你一个 无向带权 树,共有 n 个节点,编号从 0 到 n - 1。这棵树由一个二维整数数组 edges 表示,长度为 n - 1,其中 edges[i] = [ui, vi, wi] 表示存在一条连接节点 ui 和 vi 的边,权重为 wi。
103+
此外,给你一个二维整数数组 queries,其中 queries[j] = [src1j, src2j, destj]。
104+
返回一个长度等于 queries.length 的数组 answer,其中 answer[j] 表示一个子树的 最小总权重 ,使用该子树的边可以从 src1j 和 src2j 到达 destj 。
105+
这里的 子树 是指原树中任意节点和边组成的连通子集形成的一棵有效树。
106+
提示:
107+
3 <= n <= 10^5
108+
edges.length == n - 1
109+
edges[i].length == 3
110+
0 <= ui, vi < n
111+
1 <= wi <= 104
112+
1 <= queries.length <= 10^5
113+
queries[j].length == 3
114+
0 <= src1j, src2j, destj < n
115+
src1j、src2j 和 destj 互不不同。
116+
输入数据保证 edges 表示的是一棵有效的树。
117+
118+
最近公共祖先 LCA。
119+
时间复杂度 O((n+q)logn)。
120+
相似题目: E. Jamie and Tree
121+
https://codeforces.com/contest/916/problem/E
122+
3559. 给边赋权值的方案数 II
123+
https://leetcode.cn/problems/number-of-ways-to-assign-edge-weights-ii/description/
124+
rating 2413 (clist.by)
125+
*/
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3550Tests {
5+
private final Solution3550 solution3550 = new Solution3550();
6+
7+
@Test
8+
public void example1() {
9+
int[] nums = {1, 3, 2};
10+
int expected = 2;
11+
Assertions.assertEquals(expected, solution3550.smallestIndex(nums));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
int[] nums = {1, 10, 11};
17+
int expected = 1;
18+
Assertions.assertEquals(expected, solution3550.smallestIndex(nums));
19+
}
20+
21+
@Test
22+
public void example3() {
23+
int[] nums = {1, 2, 3};
24+
int expected = -1;
25+
Assertions.assertEquals(expected, solution3550.smallestIndex(nums));
26+
}
27+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3551Tests {
5+
private final Solution3551 solution3551 = new Solution3551();
6+
7+
@Test
8+
public void example1() {
9+
int[] nums = {37, 100};
10+
int expected = 1;
11+
Assertions.assertEquals(expected, solution3551.minSwaps(nums));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
int[] nums = {22, 14, 33, 7};
17+
int expected = 0;
18+
Assertions.assertEquals(expected, solution3551.minSwaps(nums));
19+
}
20+
21+
@Test
22+
public void example3() {
23+
int[] nums = {18, 43, 34, 16};
24+
int expected = 2;
25+
Assertions.assertEquals(expected, solution3551.minSwaps(nums));
26+
}
27+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3552Tests {
5+
private final Solution3552 solution3552 = new Solution3552();
6+
7+
@Test
8+
public void example1() {
9+
String[] matrix = {"A..", ".A.", "..."};
10+
int expected = 2;
11+
Assertions.assertEquals(expected, solution3552.minMoves(matrix));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
String[] matrix = {".#...", ".#.#.", ".#.#.", "...#."};
17+
int expected = 13;
18+
Assertions.assertEquals(expected, solution3552.minMoves(matrix));
19+
}
20+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /