记录 LeetCode 第 300 场周赛
本次周赛 十分可惜,很有可能 AK 的比赛却仅写出前两题。第三题带错了一个动态规划初始值,第四题没看题目,赛后十分钟给 AC 了。
战局详情
排名 | 用户名 | 得分 | 完成时间 | 题目1(3) | 题目2(4) | 题目3(5) | 题目4(6) |
---|---|---|---|---|---|---|---|
2385 / 6792 | Juruoer | 7 | 0:29:56 | 0:10:57 | 0:24:56 1 |
题目及解答
解密消息
给你字符串 key
和 message
,分别表示一个加密密钥和一段加密消息。解密 message
的步骤如下:
使用
key
中 26 个英文小写字母第一次出现的顺序作为替换表中的字母 顺序 。将替换表与普通英文字母表对齐,形成对照表。
按照对照表 替换
message
中的每个字母。空格
' '
保持不变。
- 例如,
key = "happy boy"
(实际的加密密钥会包含字母表中每个字母 至少一次),据此,可以得到部分对照表('h' -> 'a'
、'a' -> 'b'
、'p' -> 'c'
、'y' -> 'd'
、'b' -> 'e'
、'o' -> 'f'
)。
返回解密后的消息。
提示:
26 <= key.length <= 2000
key
由小写英文字母及' '
组成key
包含英文字母表中每个字符('a'
到'z'
)至少一次1 <= message.length <= 2000
message
由小写英文字母和' '
组成
示例一:
输入:key = “the quick brown fox jumps over the lazy dog”, message = “vkbs bs t suepuv”
输出:“this is a secret”
解释:对照表如上图所示。
提取 “the quick brown fox jumps over the lazy dog” 中每个字母的首次出现可以得到替换表。
示例二:
输入:key = “eljuxhpwnyrdgtqkviszcfmabo”, message = “zwx hnfx lqantp mnoeius ycgk vcnjrdb”
输出:“the five boxing wizards jump quickly”
解释:对照表如上图所示。
提取 “eljuxhpwnyrdgtqkviszcfmabo” 中每个字母的首次出现可以得到替换表。
解决方案:
模拟 + 映射:
使用一个数组来映射每个字母转换后的字母,然后模拟即可。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度: 。c
为字母种类数,为 26
,n1
为 message
长度,n2
为 key
长度。
螺旋矩阵 IV
给你两个整数:m
和 n
,表示矩阵的维数。
另给你一个整数链表的头节点 head
。
请你生成一个大小为 m x n
的螺旋矩阵,矩阵包含链表中的所有整数。链表中的整数从矩阵 左上角 开始、顺时针 按 螺旋 顺序填充。如果还存在剩余的空格,则用 -1
填充。
返回生成的矩阵。
提示:
1 <= m, n <= 1e5
1 <= m * n <= 1e5
- 链表中节点数目在范围
[1, m * n]
内 0 <= Node.val <= 1000
示例一:
输入:m = 3, n = 5, head = [3,0,2,6,8,1,7,9,4,2,5,5,0]
输出:[[3,0,2,6,8],[5,0,-1,-1,1],[5,2,4,9,7]]
解释:上图展示了链表中的整数在矩阵中是如何排布的。
注意,矩阵中剩下的空格用 -1 填充。
示例二:
输入:m = 1, n = 4, head = [0,1,2]
输出:[[0,1,2,-1]]
解释:上图展示了链表中的整数在矩阵中是如何从左到右排布的。
注意,矩阵中剩下的空格用 -1 填充。
解决方案:
模拟:
本题同 LeetCode 上 59. 螺旋矩阵 II 。只需修改数据的流向即可。这里仅给出我的代码做参考。(但其实我这个写的有点复杂,不是很好描述,有很多更清晰明了的解法可以去 LeetCode 上查找。)
代码:
1 | class Solution |
时间复杂度: ,空间复杂度: 。matrix
算结果数组不计入额外空间复杂度。
知道秘密的人数
在第 1
天,有一个人发现了一个秘密。
给你一个整数 delay
,表示每个人会在发现秘密后的 delay
天之后,每天Z 给一个新的人 分享 秘密。同时给你一个整数 forget
,表示每个人在发现秘密 forget
天之后会 忘记 这个秘密。一个人 不能 在忘记秘密那一天及之后的日子里分享秘密。
给你一个整数 n
,请你返回在第 n
天结束时,知道秘密的人数。由于答案可能会很大,请你将结果对 1e9 + 7
取余 后返回。
提示:
2 <= n <= 1000
1 <= delay < forget <= n
示例一:
输入:n = 6, delay = 2, forget = 4
输出:5
解释:
- 第 1 天:假设第一个人叫 A 。(一个人知道秘密)
- 第 2 天:A 是唯一一个知道秘密的人。(一个人知道秘密)
- 第 3 天:A 把秘密分享给 B 。(两个人知道秘密)
- 第 4 天:A 把秘密分享给一个新的人 C 。(三个人知道秘密)
- 第 5 天:A 忘记了秘密,B 把秘密分享给一个新的人 D 。(三个人知道秘密)
- 第 6 天:B 把秘密分享给 E,C 把秘密分享给 F 。(五个人知道秘密)
示例二:
输入:n = 4, delay = 1, forget = 3
输出:6
解释:
- 第 1 天:第一个知道秘密的人为 A 。(一个人知道秘密)
- 第 2 天:A 把秘密分享给 B 。(两个人知道秘密)
- 第 3 天:A 和 B 把秘密分享给 2 个新的人 C 和 D 。(四个人知道秘密)
- 第 4 天:A 忘记了秘密,B、C、D 分别分享给 3 个新的人。(六个人知道秘密)
解决方案:
动态规划:
本题动态规划的写法有好多中,其中时间复杂度 O(n^2)
的比较简单,此处给出我的时间复杂度 O(n)
的解法(也还有其他不错 的解法)。
首先有如下几条显而易见的递推关系:
- 第
i
天知道秘密的人数 = 第i - 1
天知道秘密的人数 - 第i
天新忘记秘密的人数 + 第i
天新知道秘密的人数。 - 第
i
天新忘记秘密的人数 = 在第i - forget
天新知道秘密的人数(只有这些人刚好过了forget
天到达第i
天)。 - 第
i
天新知道秘密的人数 = 第i - delay
天所有知道秘密的人数 - 从第i - delay
天之后所有忘记秘密的人数(因为forget
>delay
所以所有在第i - delay
天之后忘记秘密的人在第i - delay
天都记得秘密,而其他没有忘记秘密的人则是第i
天可以传播秘密的人)。 - 第
i
天为止所有忘记秘密的人数 = 第i - 1
天所有忘记秘密的人数 + 第i
天新忘记秘密的人数。
我们维护三个数组:
dp[i]
表示第i
天知道秘密的人数。f[i]
表示到第i
天为止所有忘记秘密的人数。k[i]
表示第i
天新知道秘密的人数。
那么有:
f[i] = f[i - 1] + k[i - forget]
。k[i] = dp[i - delay] - (f[i] - f[i - delay])
。dp[i] = dp[i - 1] - k[i - forget] + k[i]
。
代码:
1 | class Solution |
时间复杂度: ;空间复杂度: 。
网格图中递增路径的数目
给你一个 m x n
的整数网格图 grid
,你可以从一个格子移动到 4
个方向相邻的任意一个格子。
请你返回在网格图中从 任意 格子出发,达到 任意 格子,且路径中的数字是 严格递增 的路径数目。由于答案可能会很大,请将结果对 1e9 + 7
取余 后返回。
如果两条路径中访问过的格子不是完全相同的,那么它们视为两条不同的路径。
提示:
m == grid.length
n == grid[i].length
1 <= m, n <= 1000
1 <= m * n <= 1e5
1 <= grid[i][j] <= 1e5
示例一:
输入:grid = [[1,1],[3,4]]
输出:8
解释:严格递增路径包括:
- 长度为 1 的路径:[1],[1],[3],[4] 。
- 长度为 2 的路径:[1 -> 3],[1 -> 4],[3 -> 4] 。
- 长度为 3 的路径:[1 -> 3 -> 4] 。
路径数目为 4 + 3 + 1 = 8 。
示例二:
输入:grid = [[1],[2]]
输出:3
解释:严格递增路径包括:
- 长度为 1 的路径:[1],[2] 。
- 长度为 2 的路径:[1 -> 2] 。
路径数目为 2 + 1 = 3 。
解决方案:
DFS 记忆化搜索:
设 dp[i][j]
表示以 grid[i][j]
为终点的路径数,那么可以递归计算 grid[i][j]
四个方向上所有值小于其的格子的路径数。若某个格子的路径数已经计算完毕,则下次递归到它的时候可以直接返回 dp
。
代码:
1 | class Solution |
dp[i][j]
只计算一次,时间复杂度: ;空间复杂度: 。