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 d7eea25

Browse files
committed
第152场双周赛T1~T4 (4)
1 parent 5397811 commit d7eea25

File tree

8 files changed

+385
-0
lines changed

8 files changed

+385
-0
lines changed
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
public class Solution3483 {
2+
public int totalNumbers(int[] digits) {
3+
int[] cnt = new int[10];
4+
for (int v : digits) cnt[v]++;
5+
6+
int ans = 0;
7+
for (int num = 100; num <= 999; num += 2) {
8+
int a = num / 100;
9+
int b = num / 10 % 10;
10+
int c = num % 10;
11+
int[] temp = new int[10];
12+
temp[a]++;
13+
temp[b]++;
14+
temp[c]++;
15+
boolean valid = true;
16+
for (int i = 0; i < 10; i++) {
17+
if (temp[i] > cnt[i]) {
18+
valid = false;
19+
break;
20+
}
21+
}
22+
if (valid) ans++;
23+
}
24+
return ans;
25+
}
26+
}
27+
/*
28+
3483. 不同三位偶数的数目
29+
https://leetcode.cn/problems/unique-3-digit-even-numbers/description/
30+
31+
第 152 场双周赛 T1。
32+
33+
给你一个数字数组 digits,你需要从中选择三个数字组成一个三位偶数,你的任务是求出 不同 三位偶数的数量。
34+
注意:每个数字在三位偶数中都只能使用 一次 ,并且 不能 有前导零。
35+
提示:
36+
3 <= digits.length <= 10
37+
0 <= digits[i] <= 9
38+
39+
枚举 [100,999] 的每个偶数。
40+
时间复杂度 O(1000)。
41+
*/
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
public class Solution3484 {
2+
static class Spreadsheet {
3+
private final int[][] cells;
4+
5+
public Spreadsheet(int rows) {
6+
cells = new int[rows][26];
7+
}
8+
9+
public void setCell(String cell, int value) {
10+
int[] pos = parseCell(cell);
11+
cells[pos[0]][pos[1]] = value;
12+
}
13+
14+
public void resetCell(String cell) {
15+
int[] pos = parseCell(cell);
16+
cells[pos[0]][pos[1]] = 0;
17+
}
18+
19+
public int getValue(String formula) {
20+
String expr = formula.substring(1);
21+
String[] parts = expr.split("\\+");
22+
int x = getComponentValue(parts[0]);
23+
int y = getComponentValue(parts[1]);
24+
return x + y;
25+
}
26+
27+
private int[] parseCell(String cell) {
28+
char colChar = cell.charAt(0);
29+
int col = colChar - 'A';
30+
String rowStr = cell.substring(1);
31+
int row = Integer.parseInt(rowStr) - 1;
32+
return new int[]{row, col};
33+
}
34+
35+
private int getComponentValue(String s) {
36+
if (s.matches("[A-Z]\\d+")) {
37+
int[] pos = parseCell(s);
38+
return cells[pos[0]][pos[1]];
39+
} else {
40+
return Integer.parseInt(s);
41+
}
42+
}
43+
}
44+
}
45+
/*
46+
3484. 设计电子表格
47+
https://leetcode.cn/problems/design-spreadsheet/description/
48+
49+
第 152 场双周赛 T2。
50+
51+
电子表格是一个网格,它有 26 列(从 'A' 到 'Z')和指定数量的 rows。每个单元格可以存储一个 0 到 105 之间的整数值。
52+
请你实现一个 Spreadsheet 类:
53+
- Spreadsheet(int rows) 初始化一个具有 26 列(从 'A' 到 'Z')和指定行数的电子表格。所有单元格最初的值都为 0 。
54+
- void setCell(String cell, int value) 设置指定单元格的值。单元格引用以 "AX" 的格式提供(例如,"A1","B10"),其中字母表示列(从 'A' 到 'Z'),数字表示从 1 开始的行号。
55+
- void resetCell(String cell) 重置指定单元格的值为 0 。
56+
- int getValue(String formula) 计算一个公式的值,格式为 "=X+Y",其中 X 和 Y 要么 是单元格引用,要么非负整数,返回计算的和。
57+
注意: 如果 getValue 引用一个未通过 setCell 明确设置的单元格,则该单元格的值默认为 0 。
58+
提示:
59+
1 <= rows <= 10^3
60+
0 <= value <= 10^5
61+
公式保证采用 "=X+Y" 格式,其中 X 和 Y 要么是有效的单元格引用,要么是小于等于 10^5 的 非负 整数。
62+
每个单元格引用由一个大写字母 'A' 到 'Z' 和一个介于 1 和 rows 之间的行号组成。
63+
总共 最多会对 setCell、resetCell 和 getValue 调用 10^4 次。
64+
65+
哈希表模拟。
66+
*/
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import java.util.Arrays;
2+
import java.util.Comparator;
3+
4+
public class Solution3485 {
5+
public int[] longestCommonPrefix(String[] words, int k) {
6+
int n = words.length;
7+
if (k >= n) return new int[n];
8+
9+
Integer[] ids = new Integer[n];
10+
for (int i = 0; i < n; i++) ids[i] = i;
11+
Arrays.sort(ids, Comparator.comparing(i -> words[i]));
12+
13+
// 计算最大 LCP 长度和次大 LCP 长度,同时记录最大 LCP 来自哪里
14+
int mx = -1, mx2 = -1, mxI = -1;
15+
for (int i = 0; i + k - 1 < n; i++) {
16+
// 排序后,[i, i+k-1] 的 LCP 等于两端点的 LCP
17+
int lcp = calcLCP(words[ids[i]], words[ids[i + k - 1]]);
18+
if (lcp > mx) {
19+
mx2 = mx;
20+
mx = lcp;
21+
mxI = i;
22+
} else if (lcp > mx2) {
23+
mx2 = lcp;
24+
}
25+
}
26+
27+
int[] ans = new int[n];
28+
Arrays.fill(ans, mx); // 先初始化成最大 LCP 长度
29+
// 移除下标在 idx[mxI, mxI+k-1] 中的字符串,会导致最大 LCP 变成次大 LCP
30+
for (int i = mxI; i < mxI + k; i++) {
31+
ans[ids[i]] = mx2; // 改成次大 LCP 长度
32+
}
33+
return ans;
34+
}
35+
36+
// 计算 s 和 t 的最长公共前缀(LCP)长度
37+
private int calcLCP(String s, String t) {
38+
int len = Math.min(s.length(), t.length());
39+
for (int i = 0; i < len; i++) {
40+
if (s.charAt(i) != t.charAt(i)) {
41+
return i;
42+
}
43+
}
44+
return len;
45+
}
46+
}
47+
/*
48+
3485. 删除元素后 K 个字符串的最长公共前缀
49+
https://leetcode.cn/problems/longest-common-prefix-of-k-strings-after-removal/description/
50+
51+
第 152 场双周赛 T3。
52+
53+
给你一个字符串数组 words 和一个整数 k。
54+
对于范围 [0, words.length - 1] 中的每个下标 i,在移除第 i 个元素后的剩余数组中,找到任意 k 个字符串(k 个下标 互不相同)的 最长公共前缀 的 长度。
55+
返回一个数组 answer,其中 answer[i] 是 i 个元素的答案。如果移除第 i 个元素后,数组中的字符串少于 k 个,answer[i] 为 0。
56+
一个字符串的 前缀 是一个从字符串的开头开始并延伸到字符串内任何位置的子字符串。
57+
一个 子字符串 是字符串中一段连续的字符序列。
58+
提示:
59+
1 <= k <= words.length <= 10^5
60+
1 <= words[i].length <= 10^4
61+
words[i] 由小写英文字母组成。
62+
words[i].length 的总和小于等于 10^5。
63+
64+
任意 k 个 -> 连续 k 个
65+
1. 排序,那么只需要考虑长为 k 的连续子数组的 LCP
66+
2. 排序后,子数组的 LCP = LCP(子数组第一个字符串,子数组最后一个字符串)
67+
把 k 个字符串的问题转换成 2 个字符串的问题
68+
3. 如果不删除,那么答案是多少?
69+
暴力枚举所有长为 k 的子数组,根据 (2),
70+
计算所有 LCP(words[i], words[i+k-1]),取最大值,即为不删除时的答案
71+
4. 记录最大的 LCP 对应的子数组是 [mx_i, mx_{i+k-1}]
72+
记录次大的 LCP 对应的子数组是 [mx2_i, mx2_{i+k-1}]
73+
5. 考虑删除一个字符串
74+
分类讨论:
75+
a. 如果删除的字符串不在 [mx_i, mx_{i+k-1}] 中,那么答案就是不删除时的答案,即最大 LCP
76+
剩下的问题就是删除在 [mx_i, mx_{i+k-1}] 中的字符串
77+
b. 如果删除的字符串不在 [mx2_i, mx2_{i+k-1}] 中,那么答案就是次大的 LCP
78+
c. 如果删除的字符串在 [mx_i, mx_{i+k-1}] 中,又在 [mx2_i, mx2_{i+k-1}] 中,那么答案是多少?
79+
意味着这两个数组是重叠的,重叠的字符串(也就是我们删除的字符串 s)即有最大的 LCP 又有次大 LCP
80+
围绕重叠的字符串讨论,那么次大 LCP 也是 LCP 的前缀
81+
去掉字符串 s,可以再加一个交集中的其他字符串进来,仍然是 k 个字符串,且次大 LCP 是不变的
82+
那么答案就是次大的 LCP
83+
rating 2269 (clist.by)
84+
*/
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.HashMap;
4+
import java.util.List;
5+
import java.util.Map;
6+
7+
public class Solution3486 {
8+
private int[] nums;
9+
private List<int[]>[] g;
10+
private List<Integer> dis;
11+
private Map<Integer, Integer> lastDepth;
12+
private int maxLen, minNodes;
13+
14+
public int[] longestSpecialPath(int[][] edges, int[] nums) {
15+
this.nums = nums;
16+
int n = edges.length + 1;
17+
g = new ArrayList[n];
18+
Arrays.setAll(g, e -> new ArrayList<>());
19+
for (int[] e : edges) {
20+
int u = e[0], v = e[1], wt = e[2];
21+
g[u].add(new int[]{v, wt});
22+
g[v].add(new int[]{u, wt});
23+
}
24+
25+
dis = new ArrayList<>();
26+
dis.add(0);
27+
lastDepth = new HashMap<>();
28+
maxLen = -1;
29+
minNodes = 0;
30+
dfs(0, -1, 0, 0);
31+
return new int[]{maxLen, minNodes};
32+
}
33+
34+
// 本题允许窗口中的一个元素(颜色)出现两次,我们记录这个颜色在窗口中的更靠上的深度 last1
35+
private void dfs(int x, int fa, int topDepth, int last1) {
36+
int color = nums[x];
37+
int last2 = lastDepth.getOrDefault(color, 0);
38+
// 相较 3425 题,维护窗口左端点 topDepth 的逻辑变了
39+
int oldDepth = Math.min(last2, last1);
40+
topDepth = Math.max(topDepth, oldDepth);
41+
42+
int disX = dis.getLast();
43+
int len = disX - dis.get(topDepth);
44+
int nodes = dis.size() - topDepth;
45+
if (len > maxLen || len == maxLen && nodes < minNodes) {
46+
maxLen = len;
47+
minNodes = nodes;
48+
}
49+
50+
lastDepth.put(color, dis.size());
51+
for (int[] e : g[x]) {
52+
int y = e[0];
53+
if (y != fa) { // 避免访问父节点
54+
dis.add(disX + e[1]);
55+
// 相较 3425 题,额外维护 last1
56+
dfs(y, x, topDepth, Math.max(last1, last2));
57+
dis.removeLast(); // 恢复现场
58+
}
59+
}
60+
lastDepth.put(color, last2); // 恢复现场
61+
}
62+
}
63+
/*
64+
3486. 最长特殊路径 II
65+
https://leetcode.cn/problems/longest-special-path-ii/description/
66+
67+
第 152 场双周赛 T4。
68+
69+
给你一棵无向树,根节点为 0,树有 n 个节点,节点编号从 0 到 n - 1。这个树由一个长度为 n - 1 的二维数组 edges 表示,其中 edges[i] = [ui, vi, lengthi] 表示节点 ui 和 vi 之间有一条长度为 lengthi 的边。同时给你一个整数数组 nums,其中 nums[i] 表示节点 i 的值。
70+
一条 特殊路径 定义为一个从祖先节点到子孙节点的 向下 路径,路径中所有节点值都是唯一的,最多允许有一个值出现两次。
71+
返回一个大小为 2 的数组 result,其中 result[0] 是 最长 特殊路径的 长度 ,result[1] 是所有 最长 特殊路径中的 最少 节点数。
72+
提示:
73+
2 <= n <= 5 * 10^4
74+
edges.length == n - 1
75+
edges[i].length == 3
76+
0 <= ui, vi < n
77+
1 <= lengthi <= 10^3
78+
nums.length == n
79+
0 <= nums[i] <= 5 * 10^4
80+
输入保证 edges 是一棵有效的树。
81+
82+
树上滑窗。
83+
相似题目: 3425. 最长特殊路径
84+
https://leetcode.cn/problems/longest-special-path/description/
85+
rating 2929 (clist.by)
86+
*/
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3483Tests {
5+
private final Solution3483 solution3483 = new Solution3483();
6+
7+
@Test
8+
public void example1() {
9+
int[] digits = {1, 2, 3, 4};
10+
int expected = 12;
11+
Assertions.assertEquals(expected, solution3483.totalNumbers(digits));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
int[] digits = {0, 2, 2};
17+
int expected = 2;
18+
Assertions.assertEquals(expected, solution3483.totalNumbers(digits));
19+
}
20+
21+
@Test
22+
public void example3() {
23+
int[] digits = {6, 6, 6};
24+
int expected = 1;
25+
Assertions.assertEquals(expected, solution3483.totalNumbers(digits));
26+
}
27+
28+
@Test
29+
public void example4() {
30+
int[] digits = {1, 3, 5};
31+
int expected = 0;
32+
Assertions.assertEquals(expected, solution3483.totalNumbers(digits));
33+
}
34+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3484Tests {
5+
@Test
6+
public void example1() {
7+
Solution3484.Spreadsheet spreadsheet = new Solution3484.Spreadsheet(3); // 初始化一个具有 3 行和 26 列的电子表格
8+
9+
// 返回 12 (5+7)
10+
Assertions.assertEquals(12, spreadsheet.getValue("=5+7"));
11+
12+
// 设置 A1 为 10
13+
spreadsheet.setCell("A1", 10);
14+
15+
// 返回 16 (10+6)
16+
Assertions.assertEquals(16, spreadsheet.getValue("=A1+6"));
17+
18+
// 设置 B2 为 15
19+
spreadsheet.setCell("B2", 15);
20+
21+
// 返回 25 (10+15)
22+
Assertions.assertEquals(25, spreadsheet.getValue("=A1+B2"));
23+
24+
// 重置 A1 为 0
25+
spreadsheet.resetCell("A1");
26+
27+
// 返回 15 (0+15)
28+
Assertions.assertEquals(15, spreadsheet.getValue("=A1+B2"));
29+
}
30+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3485Tests {
5+
private final Solution3485 solution3485 = new Solution3485();
6+
7+
@Test
8+
public void example1() {
9+
String[] words = {"jump", "run", "run", "jump", "run"};
10+
int k = 2;
11+
int[] expected = {3, 4, 4, 3, 4};
12+
Assertions.assertArrayEquals(expected, solution3485.longestCommonPrefix(words, k));
13+
}
14+
15+
@Test
16+
public void example2() {
17+
String[] words = {"dog", "racer", "car"};
18+
int k = 2;
19+
int[] expected = {0, 0, 0};
20+
Assertions.assertArrayEquals(expected, solution3485.longestCommonPrefix(words, k));
21+
}
22+
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3486Tests {
5+
private final Solution3486 solution3486 = new Solution3486();
6+
7+
@Test
8+
public void example1() {
9+
int[][] edges = UtUtils.stringToInts2("[[0,1,1],[1,2,3],[1,3,1],[2,4,6],[4,7,2],[3,5,2],[3,6,5],[6,8,3]]");
10+
int[] nums = {1, 1, 0, 3, 1, 2, 1, 1, 0};
11+
int[] expected = {9, 3};
12+
Assertions.assertArrayEquals(expected, solution3486.longestSpecialPath(edges, nums));
13+
}
14+
15+
@Test
16+
public void example2() {
17+
int[][] edges = UtUtils.stringToInts2("[[1,0,3],[0,2,4],[0,3,5]]");
18+
int[] nums = {1, 1, 0, 2};
19+
int[] expected = {5, 2};
20+
Assertions.assertArrayEquals(expected, solution3486.longestSpecialPath(edges, nums));
21+
}
22+
}

0 commit comments

Comments
(0)

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