链接:LeetCode
给你字符串 key 和 message ,分别表示一个加密密钥和一段加密消息。解密 message 的步骤如下:
模拟遍历即可。
class Solution { public String decodeMessage(String key, String message) { char start = 'a'; HashMap<Character, Character> hash = new HashMap<>(); for(char keyChar:key.toCharArray()) { if(keyChar == ' ') continue; else if(hash.containsKey(keyChar)) continue; else { hash.put(keyChar, start); start = (char)(start + 1); } } String res = ""; for(var keyChar:message.toCharArray()) { if(keyChar == ' ') res += ' '; else res += hash.get(keyChar); } return res; } }
给你两个整数:m 和 n ,表示矩阵的维数。
另给你一个整数链表的头节点 head 。
请你生成一个大小为 m x n 的螺旋矩阵,矩阵包含链表中的所有整数。链表中的整数从矩阵 左上角 开始、顺时针 按 螺旋 顺序填充。如果还存在剩余的空格,则用 -1 填充。
返回生成的矩阵。
模拟遍历即可。
/** * 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 n, int m, ListNode head) { int[][] res = new int[n][m]; HashSet<String> set = new HashSet<>(); int state = 1; int i=0,j=0; for(int ind=0; ind< n*m ; ind ++){ if( head!=null) { res[i][j] = head.val; head = head.next; } else { res[i][j] = -1; } set.add(""+i+"_"+j); if(state == 1 && (j == m-1 || set.contains(""+i+"_"+(j+1)))) state ++; if(state == 2 && (i==n-1 || set.contains(""+(i+1)+"_"+j))) state ++; if(state == 3 && (j == 0 || set.contains(""+i+"_"+(j-1)))) state ++; if(state == 4 && (i == 0 || set.contains(""+(i-1)+"_"+j))) state = 1; if(state == 1) j++; else if(state == 2) i++; else if(state == 3) j--; else i--; } return res; } }
在第 1 天,有一个人发现了一个秘密。
给你一个整数 delay ,表示每个人会在发现秘密后的 delay 天之后,每天 给一个新的人 分享 秘密。同时给你一个整数 forget ,表示每个人在发现秘密 forget 天之后会 忘记 这个秘密。一个人 不能 在忘记秘密那一天及之后的日子里分享秘密。
给你一个整数 n ,请你返回在第 n 天结束时,知道秘密的人数。由于答案可能会很大,请你将结果对 \(10^9 + 7\) 取余 后返回。
动态规划。
只需要统计第i天新增的人数就好了,然后知道秘密的总人数其实就等于从最后一天往前推forget天的人数和。
每一个第i天知道秘密的人,都对[i+delay,i+forget)这个区间有贡献,从前往后推即可,时间复杂度\(O(n^2)\)。
可以采用前缀和优化时间,最终时间复杂度\(O(n)\)
class Solution1 { private static final int MOD = (int)1E9+7; public int peopleAwareOfSecret(int n, int delay, int forget) { long[] dp = new long[n+1]; dp[1] = 1; for(int i=1;i<n+1;++i) { for(int j=i+delay; j<Math.min(i+forget,n+1); ++j) { dp[j] += dp[i]%MOD; } } long res = 0; for(int i=0;i<forget;++i) { res += dp[n-i]; } return (int)(res%MOD); } public int peopleAwareOfSecret2(int n, int delay, int forget) { long[] dp = new long[n+1]; long[] diff = new long[n+1]; dp[0] = 0; diff[1] = 1; diff[2] = -1; for(int i=1;i<n+1;++i) { dp[i] = dp[i-1] + diff[i]; if(i+delay < n+1) diff[i+delay] += dp[i]%MOD; if(i+forget < n+1) diff[i+forget] -= dp[i]%MOD; } long res = 0; for(int i=0;i<forget;++i) { res += dp[n-i] % MOD; } return (int)(res%MOD); } }
给你一个 m x n 的整数网格图 grid ,你可以从一个格子移动到 4 个方向相邻的任意一个格子。
请你返回在网格图中从 任意 格子出发,达到 任意 格子,且路径中的数字是 严格递增 的路径数目。由于答案可能会很大,请将结果对 \(10^9 + 7\) 取余 后返回。
如果两条路径中访问过的格子不是完全相同的,那么它们视为两条不同的路径。
记忆化搜索。我们可以遍历每个格子,以这个格子为起点,往上下左右四个方向前进,如果下一个格子的值比当前格子的值大,则可以前进。定义 \(f[i][j]\) 表示以第 i 行第 j 列的格子为起点的路径数。由于路径中的数字严格递增,状态无后效性,可以用动态规划解决。
我们把四个方向可以走的格子所对应的状态 \(f[i'][j']\) 累加起来,再加上 1,即当前格子组成的长度为 1 的路径,即为 \(f[i][j]\)。
另外,利用java PriorityQueue的特性,我们也可以从小到大出发,查找每个点周围有多少个点比当前点小。
class Solution { final static int MOD = (int)1E9 + 7; final static int[][] directions = new int[][] {{1,0},{-1,0},{0,1},{0,-1}}; public int countPaths(int[][] grid) { int res = 0, n = grid.length, m = grid[0].length; int[][] memo = new int[n][m]; for(int i=0;i<n;++i) Arrays.fill(memo[i], -1); for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { res = (res + dfs(grid, memo, i, j)) % MOD; } } return res % MOD; } public int dfs(int[][] grid, int[][] memo, int i, int j) { if(memo[i][j] != -1) return memo[i][j]; int res = 0, n = grid.length, m = grid[0].length; memo[i][j] = 1; for(var dir:directions) { int inext = i+dir[0], jnext = j+dir[1]; if(inext<0 || jnext<0 || inext>n-1 || jnext>m-1 || grid[inext][jnext] <= grid[i][j]) continue; memo[i][j] = (memo[i][j]+dfs(grid, memo, inext, jnext)) % MOD; } return memo[i][j]% MOD; } // DP public int countPaths2(int[][] grid) { int res = 0, n = grid.length, m = grid[0].length; PriorityQueue<int[]> queue = new PriorityQueue<>((a,b)->b[2]-a[2]); int[][] dp = new int[n][m]; for(int i=0;i<n;++i) { for(int j=0;j<m;++j) { queue.add(new int[]{i,j,grid[i][j]}); } } while(!queue.isEmpty()) { int[] popVal = queue.poll(); int i = popVal[0],j=popVal[1],val=popVal[2]; dp[i][j] = 1; for(var dir:directions) { int inext = i+dir[0], jnext=j+dir[1]; if(inext<0 || jnext<0 || inext>n-1 || jnext>m-1 || grid[inext][jnext] <= grid[i][j]) continue; dp[i][j] = (dp[i][j] + dp[inext][jnext]) % MOD; } res = (res+dp[i][j]) % MOD; } return res; } }
参考:LeetCode