leetcode 2325 解密消息
(哈希表) O(n+m)
- 遍历 key 字符串,使用哈希表记录映射关系。
- 遍历 message 字符串,使用哈希表解密字符串。
时间复杂度
- 遍历 key 和 message 字符串各一次,故时间复杂度为 O(n+m)。
需要额外空间存储哈希表。(注意代码风格)
class Solution {public String decodeMessage(String key, String message) {StringBuilder result = new StringBuilder();char [] chs = key.toCharArray();HashMap<Character,Character> map = new HashMap<>();int mod = 0;for (char ch:chs ){if (ch!=' '&& !map.containsKey(ch)){map.put(ch, (char) ('a'+mod++));}}char []chw = message.toCharArray();for (int i = 0; i < chw.length; i++) {if (chw[i]!=' '){result.append(map.get(chw[i]));}else{result.append(" ");}}return result.toString();}}
leetcode 2326 螺旋矩阵 IV
参考螺旋打印矩阵题目,
(模拟) O(mn)
- 螺旋遍历矩阵,遍历过程中同时移动当前访问链表的指针,并填充数字。
时间复杂度
- 遍历数组一次,遍历链表一次,故总时间复杂度为 O(mn)
空间复杂度
需要 O(mn)的额外空间存储答案。
/*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode() {}* ListNode(int val) { this.val = val; }* ListNode(int val, ListNode next) { this.val = val; this.next = next; }* }*/class Solution {public int[][] spiralMatrix(int m, int n, ListNode head) {int[][] result = new int[m][n];if(n == 0 || m==0) return result;for (int i = 0; i <m ; i++) {for (int j =0;j<n;j++){result[i][j] = -1;}}// 定义四个偏移量int[] dx = {0,1,0,-1},dy = {1,0,-1,0};boolean[][] st = new boolean[m][n];for(int i = 0,x = 0,y = 0,d = 0;i < n*m;i++){result[x][y] = head.val;st[x][y] = true;int a = x + dx[d],b = y + dy[d];if(a < 0 || a >= m || b < 0 || b >= n || st[a][b] == true){d = (d + 1) % 4; // 使d在0 1 2 3间循环a = x + dx[d];b = y + dy[d];}x = a;y = b;head =head.next;if (head==null){break;}}return result;}}
leetcode 2327 知道秘密的人数
思路:(动态规划) O(n)设 f(i)表示第 i天 新增知道秘密人数。
- 初始时,f(1)=1,其余为 0待定。
- 转移时,对于 f(i),新增的人数为第 [i−forget+1,i−delay]区间内知道秘密的人数的和。
- 最终答案为[n−forget+1,n] 区间内知道秘密的人数的和。
- 为了降低时间复杂度,可以考虑使用前缀和数组快速求出区间和。不妨令 f(i) 重新表示为第 1 天到第 i天 新增 知道秘密人数的前缀和,则转移时,仅需要 f(i)=f(i−1)+f(i−delay)−f(i−forget)。最终答案为 f(n)−f(n−forget)。
时间复杂度
- 状态数为 O(n),转移时间为常数,故时间复杂度为 O(n)。
空间复杂度
- 需要 O(n) 的额外空间存储状态。
知识点:DP+前缀和+区间和
class Solution {static int mod = 1000000000+7;public int peopleAwareOfSecret(int n, int delay, int forget) {int f[] = new int[n+1];f[0]=0;f[1]=1;for(int i =2;i<=n;i++){f[i] = f[i-1];f[i] =(f[i]+ (i>delay?f[i-delay]:0))%mod;f[i] = (f[i]-(i>forget?f[i-forget]:0))%mod;}return ((f[n]-f[n-forget])%mod+mod)%mod;}}
leetcode 2328 网格图中递增路径的数目 (我当然不会了)
(记忆化搜索) O(mn)
- 设状态 f(x,y)表示以 (x,y)为终点的路径个数。由于拓扑关系比较复杂,所以需要通过记忆化搜索的方式遍历状态。
- 初始时,所有点都可以直接作为终点,故f(x,y)=1。
- 转移时,对于 (x,y),枚举其四个方向,如果存在合法的前驱方向 (tx,ty)(不越界且满足 grid(x,y)>grid(tx,ty)),递归处理 (tx,ty)后,转移 f(x,y)=f(x,y)+f(tx,ty)。
- 最终答案为 ∑f(x,y)。
时间复杂度
- 状态数共 O(mn),转移时间为常数,故总时间复杂度为 O(mn)。
空间复杂度
需要 O(mn)的额外空间存储状态数和递归调用的系统栈。
class Solution {static int mod = 1000000000+7;static int[] dx = {0,1,0,-1};static int[] dy = {1,0,-1,0};int m,n;int [][] res;public int countPaths(int[][] grid) {m = grid.length;n = grid[0].length;res = new int[m][n];for(int i = 0; i < m; i++) {for(int j = 0; j < n; j++) {res[i][j] = -1;}}int ans = 0;for(int i =0;i<m;i++){for(int j = 0;j<n;j++){ans = (ans+dp(i,j,grid))%mod;}}return ans;}public int dp(int x,int y ,int[][] grid){if(res[x][y]!=-1){return res[x][y];}int r = 1;for(int i =0;i<4;i++){int tx = x+dx[i];int ty = y+dy[i];if(tx<0||tx>=m||ty<0||ty>=n){continue;}if(grid[tx][ty]>=grid[x][y]){continue;}r=(r+dp(tx,ty,grid))%mod;}res[x][y]=rreturn r;}}
