Leetcode第300场周赛记录
作者:互联网
6108. 解密消息
题目分析:给定key
和 message
,其中key
中26个英文小写字母首次出现的顺序作为替换表中的字母顺序,听起来有点绕口,如:"the quick..."对应"abc defgh...",即key
首次出现的字母按字母表顺序映射,因此直接用哈希表模拟,将message
的每个字母替换,' '
不变。
class Solution {
public String decodeMessage(String key, String message) {
char[] keyChars = key.toCharArray();
Map<Character, Character> keyMap = new HashMap<>();
int index = 0;
for (char keyChar : keyChars) {
if (keyChar != ' ' && !keyMap.containsKey(keyChar)) {
keyMap.put(keyChar, (char) (index++ + 'a'));
}
if (index == 26) {
break;
}
}
StringBuilder sb = new StringBuilder();
for (char c : message.toCharArray()) {
sb.append(keyMap.getOrDefault(c, ' '));
}
return sb.toString();
}
}
6111. 螺旋矩阵 IV
题目分析:对矩阵左上角开始,顺时针按螺旋顺序,将整数链表的值进行填充,不足的部分用-1
填充,该类型的题搜索方式和以前的54. 螺旋矩阵大同小异,直接按该模拟方式即可。
class Solution {
public int[][] spiralMatrix(int m, int n, ListNode head) {
int[][] matrix = new int[m][n];
for (int i = 0; i < m; i++) {
Arrays.fill(matrix[i], -1); // 默认为-1,当head为空时中断全部遍历,提升效率
}
int l = 0, r = n - 1, t = 0, b = m - 1; //初始化左、右、上、下边界
while (true) {
for (int i = l; i <= r && head != null; i++) { // 左上角出发
matrix[t][i] = head.val;
head = head.next;
}
if (++t > b) break; // 上边界下移,判断是否大于下边界
for (int i = t; i <= b && head != null; i++) { // 右上角出发
matrix[i][r] = head.val;
head = head.next;
}
if (--r < l) break; // 右边界左移,判断是否小于左边界
for (int i = r; i >= l && head != null; i--) { // 右下角出发
matrix[b][i] = head.val;
head = head.next;
}
if (--b < t) break; // 下边界上移,判断是否大于上边界
for (int i = b; i >= t && head != null; i--) { // 左下角触发
matrix[i][l] = head.val;
head = head.next;
}
if (++l > r) break; // 左边界右移,判断是否大于右边界
}
return matrix;
}
}
6109. 知道秘密的人数
题目分析:第1
天一个人发现秘密,给定变量n
,delay
,forget
,从那天在静默期delay
天后的每一天分享秘密给新人,在超期forget
天后则忘记秘密。问n
天结束时有几个人知道秘密,结果要对 109+7 取余。很遗憾这题折腾了1小时多就AC不了,第一想法就是用DFS,但这是我的弱项,所以写的DFS是有问题的,而且是1天1天递增的,效率太低了。该题要过滤重复的搜索,使用dfs+一维记忆化来解决这个问题:
// 解法一:dfs+一维记忆化
/**
Java 记忆化搜索:
我们记dfs(i)为第i天发现的秘密的人包含自己在内一共可以使得后面多少人知道秘密
i从i+delay天起,到i+forget-1天都是可以将秘密散播出去的
也就是[min(i+delay,n),min(i+forget-1,n)]=[a,b]这个时间段是i的传播阶段
此时知道秘密的人数有1+∑dfs(a,b)
同时应该注意知道了秘密的人会忘记秘密,因此也会有一个期限
这里由于子问题的出现可以使用记忆化减少搜索次数
*/
class Solution {
int n, delay, forget;
int MOD = (int) 1e9 + 7;
int[] memo;
public int peopleAwareOfSecret(int _n, int _delay, int _forget) {
n = _n;
delay = _delay;
forget = _forget;
memo = new int[n + 1]; // 初始化一维记录
return dfs(1);
}
public int dfs(int day) {
if (day + delay > n) { // 如果在第n天才能传播,只有当事人知道
return 1;
}
if (memo[day] != 0) { // 如果当天已有深搜记录,直接返回
return memo[day];
}
int l = Math.min(day + delay, n), r = Math.min(day + forget - 1, n); // 秘密的传播范围,[静默期结束-忘记)
long res = day + forget <= n ? 0 : 1; // 如果当事人在n天内给忘了,那结果为0,否则1
for (int i = l; i <= r; i++) {
int t = dfs(i);
memo[i] = t; // 记录结果
res = (res + t) % MOD;
}
return (int) res; // 返回全部结果
}
}
// 解法二:用哈希表模拟
class Solution {
public int peopleAwareOfSecret(int n, int delay, int forget) {
long mod = 1000000007L;
Map<Integer, Long> perMap = new HashMap<>(); // day-knowNum
long res = 1L;
perMap.put(1, 1L); // 第一天只有1人知道
for (int day = 2; day <= n; day++) {
long add = 0, del= 0; // 当天新增知道的人数,忘记的人数
for (Map.Entry<Integer, Long> entry : perMap.entrySet()) {
if (day - entry.getKey() >= forget) { // 如果当天的人数满足忘记条件,则记到del,将map对应val设置0
del += entry.getValue() % mod;
entry.setValue(0L);
} else if (day - entry.getKey() >= delay) { // 如果当天的人数满足传播秘密条件,则记到add
add += entry.getValue() % mod;
}
}
res = (res + add - del) % mod; // 对当天的新增,忘记人数累加
if (add != 0) {
perMap.put(day, add); // 如果当天有新增的人数,存到map
}
}
return (int) res;
}
}
6110. 网格图中递增路径的数目
题目分析:给定m x n
的整数网络图grid
,从任意各自触发,到达任意格子,但是路径中的数字是严格递增的,结果对 109+7 取余。依据题意,可以依次遍历每个格子,往上下左右四个方向前进,如果下一个格子比当前格子大,可以前进。使用memo[i][j]
保持从grid[i][j]
出发的递增路径数,dfs(i,j)
的主逻辑:grid[i][j]
出发的递增路径数=自身1条+上下左右出发严格递增路径之和。注意,如果路径不能重复走,那么需要加个变量来标记如vis[i][j]=true
// dfs+二维记忆化
class Solution {
int MOD = (int) 1e9 + 7;
int[][] dirs = {{1,0}, {-1,0}, {0,1}, {0,-1}};
int[][] grid, memo;
int m, n;
public int countPaths(int[][] _grid) {
grid = _grid;
m = grid.length;
n = grid[0].length;
memo = new int[m][n]; // 初始化二维记录
for (int i = 0; i < m; i++) {
Arrays.fill(memo[i], -1);
}
int ans = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
ans = (ans + dfs(i, j)) % MOD; // 对网络的每个节点进行深搜求结果
}
}
return ans;
}
public int dfs(int i, int j) {
if (memo[i][j] != -1) {
return memo[i][j]; // 该位置已搜索过,直接返回
}
long res = 1L; // 自身路径
for (int[] dir : dirs) { // 四个方向出发
int dx = i + dir[0];
int dy = j + dir[1];
if (dx >= 0 && dx < m && dy >= 0 && dy < n && grid[dx][dy] > grid[i][j]) {
res = (res + dfs(dx, dy)) % MOD; // 如果新的位置满足在矩阵内,且大于旧位置,继续深搜,结果累加
}
}
memo[i][j] = (int) res; // 记录结果
return memo[i][j]; // 返回结果
}
}
标签:周赛,forget,300,memo,day,delay,int,grid,Leetcode 来源: https://www.cnblogs.com/loghorizion/p/16440534.html