Skip to content

Commit c2c695c

Browse files
committed
1255 & 第334场周赛T1~T4 (5)
1 parent 0728da4 commit c2c695c

File tree

12 files changed

+456
-24
lines changed

12 files changed

+456
-24
lines changed
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
public class Solution1255 {
2+
public int maxScoreWords(String[] words, char[] letters, int[] score) {
3+
int n = words.length;
4+
5+
// 预处理 fs[i] 表示第 i 个单词分数;cost[i] 表示第 i 个单词所需字母
6+
int[] fs = new int[n];
7+
int[][] cost = new int[n][26];
8+
for (int i = 0; i < n; i++) {
9+
int s = 0;
10+
for (char ch : words[i].toCharArray()) {
11+
cost[i][ch - 'a']++;
12+
s += score[ch - 'a'];
13+
}
14+
fs[i] = s;
15+
}
16+
// tot 表示各字符可用的数量
17+
int[] tot = new int[26];
18+
for (char ch : letters) {
19+
tot[ch - 'a']++;
20+
}
21+
22+
int max = 0;
23+
// 状态压缩
24+
for (int mask = 1; mask < (1 << n); mask++) {
25+
int[] need = new int[26];
26+
int s = 0;
27+
for (int k = 0; k < n; k++) {
28+
if (((mask >> k) & 1) == 1) {
29+
for (int i = 0; i < 26; i++) {
30+
need[i] += cost[k][i];
31+
if (need[i] > tot[i]) {
32+
// 状态不成立
33+
s = -1;
34+
break;
35+
}
36+
}
37+
if (s < 0) break;
38+
s += fs[k];
39+
}
40+
}
41+
max = Math.max(max, s);
42+
}
43+
return max;
44+
}
45+
}
46+
/*
47+
1255. 得分最高的单词集合
48+
https://leetcode.cn/problems/maximum-score-words-formed-by-letters/
49+
50+
你将会得到一份单词表 words,一个字母表 letters (可能会有重复字母),以及每个字母对应的得分情况表 score。
51+
请你帮忙计算玩家在单词拼写游戏中所能获得的「最高得分」:能够由 letters 里的字母拼写出的 任意 属于 words 单词子集中,分数最高的单词集合的得分。
52+
单词拼写游戏的规则概述如下:
53+
- 玩家需要用字母表 letters 里的字母来拼写单词表 words 中的单词。
54+
- 可以只使用字母表 letters 中的部分字母,但是每个字母最多被使用一次。
55+
- 单词表 words 中每个单词只能计分(使用)一次。
56+
- 根据字母得分情况表score,字母 'a', 'b', 'c', ... , 'z' 对应的得分分别为 score[0], score[1], ..., score[25]。
57+
- 本场游戏的「得分」是指:玩家所拼写出的单词集合里包含的所有字母的得分之和。
58+
提示:
59+
1 <= words.length <= 14
60+
1 <= words[i].length <= 15
61+
1 <= letters.length <= 100
62+
letters[i].length == 1
63+
score.length == 26
64+
0 <= score[i] <= 10
65+
words[i] 和 letters[i] 只包含小写的英文字母。
66+
67+
状态压缩枚举
68+
时间复杂度 O(n * 2^n)
69+
空间复杂度 O(n)
70+
*/
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution1255Tests {
5+
private final Solution1255 solution1255 = new Solution1255();
6+
7+
@Test
8+
public void example1() {
9+
String[] words = {"dog", "cat", "dad", "good"};
10+
char[] letters = UtUtils.stringToChars("""
11+
["a","a","c","d","d","d","g","o","o"]
12+
""");
13+
int[] score = {1, 0, 9, 5, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
14+
int expected = 23;
15+
Assertions.assertEquals(expected, solution1255.maxScoreWords(words, letters, score));
16+
}
17+
18+
@Test
19+
public void example2() {
20+
String[] words = {"xxxz", "ax", "bx", "cx"};
21+
char[] letters = UtUtils.stringToChars("""
22+
["z","a","b","c","x","x","x"]
23+
""");
24+
int[] score = {4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 10};
25+
int expected = 27;
26+
Assertions.assertEquals(expected, solution1255.maxScoreWords(words, letters, score));
27+
}
28+
29+
@Test
30+
public void example3() {
31+
String[] words = {"leetcode"};
32+
char[] letters = UtUtils.stringToChars("""
33+
["l","e","t","c","o","d"]
34+
""");
35+
int[] score = {0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0};
36+
int expected = 0;
37+
Assertions.assertEquals(expected, solution1255.maxScoreWords(words, letters, score));
38+
}
39+
}

leetcode-23/src/main/java/Solution2212.java

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
public class Solution2212 {
22
public int[] maximumBobPoints(int numArrows, int[] aliceArrows) {
3-
int maxScore = 0;
4-
int[] res = new int[12];
3+
// 常数 12
4+
int n = aliceArrows.length;
55

6-
// 状态压缩 2^12 = 4096
7-
for (int state = 0; state < (1 << 12); state++) {
8-
// bob
6+
int maxScore = 0;
7+
int[] res = new int[n];
8+
for (int mask = 0; mask < (1 << n); mask++) {
9+
// bob 当前状态的分数,箭数,射箭情况
910
int score = 0;
10-
int arrows = numArrows;
11-
int[] bobArrows = new int[12];
11+
int need = 0;
12+
int[] bobArrows = new int[n];
1213

13-
// 贪心,从分值高的开始
14-
for (int k = 11; k >= 0; k--) {
15-
// 第 k 位被选中
16-
if (((state >> k) & 1) == 1) {
17-
int needArrows = aliceArrows[k] + 1;
18-
// can
19-
if (arrows - needArrows >= 0 && k != 0) {
20-
arrows -= needArrows;
21-
score += k;
22-
bobArrows[k] = needArrows;
23-
} else {
24-
bobArrows[k] = arrows;
25-
arrows = 0;
14+
// 从分值高的开始
15+
for (int k = n - 1; k >= 1; k--) {
16+
if (((mask >> k) & 1) == 1) {
17+
bobArrows[k] = aliceArrows[k] + 1;
18+
need += bobArrows[k];
19+
if (need > numArrows) {
20+
// 状态不成立
21+
score = -1;
22+
break;
2623
}
24+
score += k;
2725
}
28-
if (score >= maxScore) {
29-
maxScore = score;
30-
res = bobArrows;
31-
}
26+
}
27+
if (maxScore < score) {
28+
// 多余的箭全部射到 0 区域
29+
bobArrows[0] = numArrows - need;
30+
maxScore = score;
31+
res = bobArrows;
3232
}
3333
}
3434
return res;
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import java.util.Arrays;
2+
import java.util.Comparator;
3+
import java.util.PriorityQueue;
4+
5+
public class Solution6366 {
6+
private static final int[][] DIRECTIONS = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
7+
8+
public int minimumTime(int[][] grid) {
9+
int M = grid.length;
10+
int N = grid[0].length;
11+
12+
// “困毙”
13+
if (grid[0][1] > 1 && grid[1][0] > 1) {
14+
return -1;
15+
}
16+
17+
PriorityQueue<int[]> queue = new PriorityQueue<>(Comparator.comparingInt(o -> o[2]));
18+
queue.add(new int[]{0, 0, 0});
19+
boolean[][] visited = new boolean[M][N];
20+
// 到达 grid[i][j] 所需的最少时间
21+
int[][] t = new int[M][N];
22+
for (int i = 0; i < M; i++) {
23+
Arrays.fill(t[i], Integer.MAX_VALUE);
24+
}
25+
t[0][0] = 0;
26+
while (!queue.isEmpty()) {
27+
int[] tuple = queue.remove();
28+
int cx = tuple[0], cy = tuple[1], ct = tuple[2];
29+
if (visited[cx][cy]) {
30+
continue;
31+
}
32+
visited[cx][cy] = true;
33+
34+
for (int[] dir : DIRECTIONS) {
35+
int nx = cx + dir[0];
36+
int ny = cy + dir[1];
37+
if (nx >= 0 && nx < M && ny >= 0 && ny < N) {
38+
// “走闲”
39+
int nt = ct + 1 + (Math.max(0, grid[nx][ny] - ct) / 2 * 2);
40+
if (t[nx][ny] > nt) {
41+
t[nx][ny] = nt;
42+
queue.add(new int[]{nx, ny, nt});
43+
}
44+
}
45+
}
46+
}
47+
return t[M - 1][N - 1];
48+
}
49+
}
50+
/*
51+
6366. 在网格图中访问一个格子的最少时间
52+
https://leetcode.cn/problems/minimum-time-to-visit-a-cell-in-a-grid/
53+
54+
第 334 场周赛 T4。
55+
56+
给你一个 m x n 的矩阵 grid ,每个元素都为 非负 整数,其中 grid[row][col] 表示可以访问格子 (row, col) 的 最早 时间。
57+
也就是说当你访问格子 (row, col) 时,最少已经经过的时间为 grid[row][col] 。
58+
你从 最左上角 出发,出发时刻为 0 ,你必须一直移动到上下左右相邻四个格子中的 任意 一个格子(即不能停留在格子上)。每次移动都需要花费 1 单位时间。
59+
请你返回 最早 到达右下角格子的时间,如果你无法到达右下角的格子,请你返回 -1 。
60+
提示:
61+
m == grid.length
62+
n == grid[i].length
63+
2 <= m, n <= 1000
64+
4 <= m * n <= 10^5
65+
0 <= grid[i][j] <= 10^5
66+
grid[0][0] == 0
67+
68+
堆优化 Dijkstra 最短路。
69+
首先,特判 `grid[0][1] > 1 && grid[1][0] > 1` 情况,此时“困毙”(“困毙”:中国象棋术语。指轮到行棋的一方,棋子没有被将军,但所有棋子被困在原地无子可动,即被困毙)。
70+
否则,可以通过“走闲”来凑时间,总能到达终点(“走闲”:中国象棋术语。表示行棋方无意进攻,走闲是用于等待时机或用于防守的战术)。
71+
注意时间奇偶性:因“走闲”一次时间 +2。如:3->5 需要 t+2+1;3->6 同样需要 t+2+1。
72+
最后 dijkstra 求最短路即可。
73+
时间复杂度 O(mnlogmn)
74+
本题还有二分 + BFS 解法。
75+
相似题目: 778. 水位上升的泳池中游泳
76+
https://leetcode.cn/problems/swim-in-rising-water/
77+
*/
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import java.util.Arrays;
2+
3+
public class Solution6367 {
4+
public int maxNumOfMarkedIndices(int[] nums) {
5+
int n = nums.length;
6+
Arrays.sort(nums);
7+
8+
int left = 1;
9+
int right = n / 2 + 1;
10+
while (left < right) {
11+
int mid = left + (right - left) / 2;
12+
// 边界二分 F, F,..., F, [T, T,..., T]
13+
// ----------------------^
14+
if (!checkMid(nums, mid)) {
15+
right = mid;
16+
} else {
17+
left = mid + 1;
18+
}
19+
}
20+
return (left - 1) * 2;
21+
}
22+
23+
// 是否可以构造 k 对匹配(最小 k 个数和最大 k 个数 一一匹配)
24+
private boolean checkMid(int[] nums, int k) {
25+
int n = nums.length;
26+
for (int i = 0; i < k; i++) {
27+
if (nums[i] * 2 > nums[n - k + i]) {
28+
return false;
29+
}
30+
}
31+
return true;
32+
}
33+
}
34+
/*
35+
6367. 求出最多标记下标
36+
https://leetcode.cn/problems/find-the-maximum-number-of-marked-indices/
37+
38+
第 334 场周赛 T3。
39+
40+
给你一个下标从 0 开始的整数数组 nums 。
41+
一开始,所有下标都没有被标记。你可以执行以下操作任意次:
42+
- 选择两个 互不相同且未标记 的下标 i 和 j ,满足 2 * nums[i] <= nums[j] ,标记下标 i 和 j 。
43+
请你执行上述操作任意次,返回 nums 中最多可以标记的下标数目。
44+
提示:
45+
1 <= nums.length <= 10^5
46+
1 <= nums[i] <= 10^9
47+
48+
二分 + 贪心。
49+
二分查找转化为判定问题:判定是否可以构造 k 对匹配。根据贪心:当最小 k 个数和最大 k 个数一一匹配时,配对数最大。
50+
时间复杂度 O(nlogn)
51+
*/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public class Solution6368 {
2+
public int[] divisibilityArray(String word, int m) {
3+
int n = word.length();
4+
5+
long x = 0L;
6+
int[] div = new int[n];
7+
for (int i = 0; i < n; i++) {
8+
x = x * 10 + (word.charAt(i) - '0');
9+
if (x % m == 0) {
10+
div[i] = 1;
11+
}
12+
x %= m;
13+
}
14+
return div;
15+
}
16+
}
17+
/*
18+
6368. 找出字符串的可整除数组
19+
https://leetcode.cn/problems/find-the-divisibility-array-of-a-string/
20+
21+
第 334 场周赛 T2。
22+
23+
给你一个下标从 0 开始的字符串 word ,长度为 n ,由从 0 到 9 的数字组成。另给你一个正整数 m 。
24+
word 的 可整除数组 div 是一个长度为 n 的整数数组,并满足:
25+
- 如果 word[0,...,i] 所表示的 数值 能被 m 整除,div[i] = 1
26+
- 否则,div[i] = 0
27+
返回 word 的可整除数组。
28+
提示:
29+
1 <= n <= 10^5
30+
word.length == n
31+
word 由数字 0 到 9 组成
32+
1 <= m <= 10^9
33+
34+
贪心。模运算。
35+
如果 x 可以整除 m,那么 x * 10 也必然可以整除 m。取余之后不影响结果。
36+
时间复杂度 O(n)
37+
*/
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
public class Solution6369 {
2+
public int[] leftRigthDifference(int[] nums) {
3+
int n = nums.length;
4+
5+
// 前缀和
6+
int[] preSum = new int[n + 1];
7+
for (int i = 0; i < n; i++) {
8+
preSum[i + 1] = preSum[i] + nums[i];
9+
}
10+
11+
int[] ans = new int[n];
12+
for (int i = 0; i < n; i++) {
13+
int leftSum = preSum[i];
14+
int rightSum = preSum[n] - preSum[i + 1];
15+
ans[i] = Math.abs(leftSum - rightSum);
16+
}
17+
return ans;
18+
}
19+
}
20+
/*
21+
6369. 左右元素和的差值
22+
https://leetcode.cn/problems/left-and-right-sum-differences/
23+
24+
第 334 场周赛 T1。
25+
26+
给你一个下标从 0 开始的整数数组 nums ,请你找出一个下标从 0 开始的整数数组 answer ,其中:
27+
- answer.length == nums.length
28+
- answer[i] = |leftSum[i] - rightSum[i]|
29+
其中:
30+
- leftSum[i] 是数组 nums 中下标 i 左侧元素之和。如果不存在对应的元素,leftSum[i] = 0 。
31+
- rightSum[i] 是数组 nums 中下标 i 右侧元素之和。如果不存在对应的元素,rightSum[i] = 0 。
32+
返回数组 answer 。
33+
提示:
34+
1 <= nums.length <= 1000
35+
1 <= nums[i] <= 10^5
36+
37+
前缀和。leftSum[i] = [0,i-1] 区间和;rightSum[i] = [i+1,n-1] 区间和。
38+
时间复杂度 O(n)
39+
*/

0 commit comments

Comments
 (0)