算法分类 相关网址 liuyubobobo /Play-with-Algorithm-Interview
liweiwei1419
CodeTop
SharingSource /**LogicStack-LeetCode **宫水三叶
模版 leetcode提交模版 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 package leetcode.editor.cn;public class MySolution { public static void main (String[] args) { Solution solution = new MySolution ().new Solution (); } class Solution { public void method (int x) { } } }
动态规划 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Solution { public int rob (int [] nums) { int n = nums.length; int [] dp = new int [n]; if (n == 1 ) { return nums[0 ]; } dp[0 ] = nums[0 ]; dp[1 ] = Math.max(nums[0 ], nums[1 ]); for (int i=2 ; i<n; i++) { dp[i] = Math.max(nums[i] + dp[i-2 ], dp[i-1 ]); } return dp[n-1 ]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class Solution { public String longestPalindrome (String s) { char [] chars = s.toCharArray(); int n = chars.length; boolean [][] dp = new boolean [n][n]; if (n < 2 ) { return s; } int ansCount = 0 ; String ansStr = "" + chars[0 ]; for (int i = 0 ; i < n; i++) { dp[i][i] = true ; } for (int step = 2 ; step <= n; step++) { for (int i = 0 ; i < n-step+1 ; i++) { int j = i + step - 1 ; if (chars[i] == chars[j]) { if (step == 2 ) { dp[i][j] = true ; } else { dp[i][j] = dp[i+1 ][j-1 ]; } } else { dp[i][j] = false ; } if (dp[i][j] && step > ansCount) { ansCount = step; ansStr = s.substring(i, j+1 ); } } } return ansStr; } }
回溯 + 动态规划预处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 class Solution { public List<List<String>> partition (String s) { char [] chars = s.toCharArray(); int n = chars.length; boolean [][] dp = new boolean [n][n]; for (int step = 1 ; step <= n; step++) { for (int i = 0 ; i < n - step + 1 ; i++) { int j = i + step - 1 ; if (step == 1 ) { dp[i][j] = true ; } else if (step == 2 ) { if (chars[i] == chars[j]) { dp[i][j] = true ; } else { dp[i][j] = false ; } } else { if (chars[i] == chars[j]) { dp[i][j] = dp[i+1 ][j-1 ]; } else { dp[i][j] = false ; } } } } List<List<String>> anses = new ArrayList (); dfsTrace(anses, new ArrayList <>(), 0 , chars, dp); return anses; } public void dfsTrace (List<List<String>> anses, List<String> curAns, int curIndex, char [] chars, boolean [][] dp) { if (curIndex == chars.length) { anses.add(new ArrayList <>(curAns)); return ; } for (int i = curIndex; i < chars.length; i++) { if (dp[curIndex][i]) { curAns.add(new String (Arrays.copyOfRange(chars, curIndex, i + 1 ))); dfsTrace(anses, curAns, i + 1 , chars, dp); curAns.remove(curAns.size() - 1 ); } } } }
注意:此处用$f(i)$代表以第$i$个数结尾的「连续子数组的最大和」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public int maxSubArray (int [] nums) { int n = nums.length; int [] dp = new int [n]; int ans = 0 ; dp[0 ] = nums[0 ]; for (int i = 1 ; i < n; i++) { dp[i] = Math.max(dp[i-1 ] + nums[i], nums[i]); ans = Math.max(dp[i], ans); } return ans; } }
这个不是动态规划,是二分,为了下面的 最长递增子序列的 动态+贪心+二分算法 的基础。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public int searchInsert (int [] nums, int target) { int left = 0 , right = nums.length-1 ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (nums[mid] == target) { left = mid; break ; } else if (nums[mid] > target) { right = mid - 1 ; } else { left = mid + 1 ; } } return left; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 class Solution { public int lengthOfLIS (int [] nums) { int [] dp = new int [nums.length]; int ans = 1 ; Arrays.fill(dp, 1 ); for (int i=1 ; i<nums.length; i++) { for (int j=0 ; j<i; j++) { if (nums[i] > nums[j]) { dp[i] = Math.max(dp[i], dp[j] + 1 ); } } ans = Math.max(ans, dp[i]); } return ans; } } package leetcode.editor.cn;import java.util.*;public class P300LongestIncreasingSubsequence { public static void main (String[] args) { Solution solution = new P300LongestIncreasingSubsequence ().new Solution (); System.out.println(solution.lengthOfLIS(new int []{7 ,7 ,7 ,7 ,7 ,7 ,7 })); } class Solution { public int lengthOfLIS (int [] nums) { int [] g = new int [nums.length + 1 ]; int len = 1 ; g[len] = nums[0 ]; for (int i=1 ; i<nums.length; i++) { int left = 1 , right = len; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (g[mid] == nums[i]) { left = mid; break ; } else if (g[mid] > nums[i]) { right = mid - 1 ; } else { left = mid + 1 ; } } len = Math.max(left, len); g[left] = nums[i]; } return len; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 class Solution { public int maxEnvelopes (int [][] envelopes) { Arrays.sort(envelopes, (e1, e2) -> { if (e1[0 ] == e2[0 ]) { return e2[1 ] - e1[1 ]; } return e1[0 ] - e2[0 ]; }); int n = envelopes.length; int [] g = new int [n+1 ]; int ans = 1 ; g[1 ] = envelopes[0 ][1 ]; for (int i = 1 ; i < n; i++) { int left = 1 , right = ans; while (left <= right) { int mid = left + (right - left >> 1 ); if (envelopes[i][1 ] == g[mid]) { left = mid; break ; } else if (envelopes[i][1 ] < g[mid]) { right = mid - 1 ; } else { left = mid + 1 ; } } ans = Math.max(ans, left); g[left] = envelopes[i][1 ]; } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 class Solution { public int minFlipsMonoIncr (String s) { int n = s.length(); int [] g = new int [n + 1 ]; int gLen = 1 ; g[gLen] = s.charAt(0 ) - '0' ; for (int i = 1 ; i < s.length(); i++) { int left = 1 , right = gLen; int num = s.charAt(i) - '0' ; while (left <= right) { int mid = left + ((right - left) >> 1 ); if (g[mid] <= num) { left = mid + 1 ; } else { right = mid - 1 ; } } g[left] = num; gLen = Math.max(gLen, left); } return n - gLen; } } class Solution { public int minFlipsMonoIncr (String s) { int len = s.length(); int [][] dp = new int [len][2 ]; dp[0 ][0 ] = s.charAt(0 ) == '0' ? 0 : 1 ; dp[0 ][1 ] = s.charAt(0 ) == '0' ? 1 : 0 ; for (int i = 1 ; i < len; i++) { dp[i][0 ] = dp[i-1 ][0 ] + s.charAt(0 ) == '0' ? 0 : 1 ; dp[i][1 ] = Math.max(dp[i-1 ][0 ], dp[i-1 ][1 ]) + s.charAt(0 ) == '0' ? 1 : 0 ; } return Math.max(dp[len-1 ][0 ], dp[len-1 ][1 ]); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution { public int findNumberOfLIS (int [] nums) { int n = nums.length; int [] dp = new int [n]; int [] g = new int [n]; int maxCount = 1 ; Arrays.fill(dp, 1 ); Arrays.fill(g, 1 ); for (int i = 0 ; i < n; i++) { for (int j = 0 ; j < i; j++) { if (nums[i] > nums[j]) { if (dp[i] < dp[j] + 1 ) { dp[i] = dp[j] + 1 ; g[i] = g[j]; } else if (dp[i] == dp[j] + 1 ) { g[i] += g[j]; } } } maxCount = Math.max(maxCount, dp[i]); } int finalMaxCount = maxCount; return IntStream.range(0 , dp.length).filter(index -> dp[index] == finalMaxCount).map(index -> g[index]).sum(); } }
最长公共子序列,以及它的第一位数 未验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.*;import java.util.stream.IntStream;public class Main1 { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = Integer.parseInt(scanner.nextLine()); int [] nums = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); int [] dp = new int [n]; int [] g = IntStream.range(0 , n).map(i -> nums[i]).toArray(); Arrays.fill(dp, 1 ); for (int i = 1 ; i < n; i++) { for (int j = 0 ; j < i; j++) { if (nums[j] < nums[i]) { if (dp[i] < dp[j] + 1 ) { dp[i] = dp[j] + 1 ; g[i] = g[j]; } } } } int ansIndex = 0 ; int maxCount = 0 ; for (int i = 0 ; i < n; i++) { if (maxCount < dp[i]) { maxCount = dp[i]; ansIndex = i; } } System.out.println(g[ansIndex] + " " + maxCount); } }
注意 :当两个数组求公共子序列时(LCS),当有一个数组元素各不相同时,可以转为(LIS)
具体做法是,先map存储target中的元素和下标,然后一个个遍历arr(此处需要存的是元素不重复的下标 )
若和target有公共元素(与map中是有contains该key),list中存储该公共元素的target中的下标
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public int longestCommonSubsequence (String text1, String text2) { int len1 = text1.length(), len2 = text2.length(); int [][] dp = new int [len1+1 ][len2+1 ]; for (int i = 0 ; i < len1; i++) { dp[i][0 ] = 0 ; } for (int i = 0 ; i < len2; i++) { dp[0 ][i] = 0 ; } for (int i = 1 ; i <= len1; i++) { char c1 = text1.charAt(i-1 ); for (int j = 1 ; j <= len2; j++) { char c2 = text2.charAt(j-1 ); if (c1 == c2) { dp[i][j] = dp[i-1 ][j-1 ] + 1 ; } else { dp[i][j] = Math.max(dp[i-1 ][j], dp[i][j-1 ]); } } } return dp[len1][len2]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution { public int findLUSlength (String[] strs) { int n = strs.length; int ans = 0 ; for (int i = 0 ; i < n; i++) { if (strs[i].length() > ans) { boolean flag = false ; for (int j = 0 ; j < n; j++) { if (j != i && checkLCS(strs[j], strs[i])) { flag = true ; break ; } } if (!flag) { ans = strs[i].length(); } } } return ans = = 0 ? -1 : ans; } public boolean checkLCS (String s, String childS) { int n1 = s.length(), n2 = childS.length(); int [][] dp = new int [n1+1 ][n2+1 ]; for (int i = 1 ; i <= n1; i++) { for (int j = 1 ; j <= n2; j++) { if (s.charAt(i-1 ) == childS.charAt(j-1 )) { dp[i][j] = dp[i-1 ][j-1 ] + 1 ; } else { dp[i][j] = Math.max(dp[i][j-1 ], dp[i-1 ][j]); } } } if (dp[n1][n2] == n2) { return true ; } return false ; } }
参考链接:【面试高频系列】LCS 问题与 LIS 问题的相互关系,以及 LIS 问题的最优解证明
具体转换 target元素均不相同,那么先把target的下标与元素一一映射,然后将映射的结果放到arr数组中去(这个时候新数组存的是arr的元素对应在target的下标了,当然arr中不存在映射的,不加入了),在arr数组中使用LIS。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public int minOperations (int [] target, int [] arr) { Map<Integer, Integer> map = IntStream.range(0 , target.length).boxed() .collect(Collectors.toMap(index -> target[index], Function.identity(), (a, b) -> a)); int [] indexNums = Arrays.stream(arr).filter(map::containsKey).map(map::get).toArray(); int n = indexNums.length; if (n == 0 ) { return target.length; } int [] dp = new int [n]; int [] g = new int [n + 1 ]; Arrays.fill(g, Integer.MAX_VALUE); g[0 ] = -1 ; for (int i = 0 ; i < n; i++) { int left = 0 , right = i; while (left <= right) { int mid = left + (right - left >> 1 ); if (g[mid] >= indexNums[i]) { right = mid - 1 ; } else { left = mid + 1 ; } } dp[i] = right == -1 ? 1 : right + 1 ; g[dp[i]] = Math.min(indexNums[i], g[dp[i]]); } return target.length - Arrays.stream(dp).max().getAsInt(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public int numDecodings (String s) { s = ' ' + s; int n = s.length(); int [] dp = new int [s.length()]; dp[0 ] = 1 ; for (int i=1 ; i<n; i++) { int a = s.charAt(i) - '0' ; int b = (s.charAt(i-1 ) - '0' ) * 10 + a; if (a >= 1 && a <= 9 ) { dp[i] = dp[i-1 ]; } if (b >= 10 && b <= 26 ) { dp[i] += dp[i-2 ]; } } return dp[n-1 ]; } }
一维数组也可以的嗷!
198和213,我觉得还是官方题解比较好一点,建议不要看下面的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public int rob (int [] nums) { int n = nums.length; if (n == 0 ) { return 0 ; } if (n == 1 ) { return nums[0 ]; } int [][] dp = new int [n][n]; for (int i=1 ; i<=n-2 ; i++) { dp[i][0 ] = Math.max(dp[i-1 ][0 ], dp[i-1 ][1 ]); dp[i][1 ] = dp[i-1 ][0 ] + nums[i]; } int a = Math.max(dp[n-2 ][0 ]+nums[n-1 ], dp[n-2 ][1 ]); dp[0 ][0 ] = 0 ; dp[0 ][1 ] = nums[0 ]; for (int i=1 ; i<=n-2 ; i++) { dp[i][0 ] = Math.max(dp[i-1 ][0 ], dp[i-1 ][1 ]); dp[i][1 ] = dp[i-1 ][0 ] + nums[i]; } int b = Math.max(dp[n-2 ][0 ], dp[n-2 ][1 ]); return Math.max(a, b); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int getMoneyAmount (int n) { int [][] dp = new int [n+2 ][n+2 ]; for (int step=2 ; step<=n; step++) { for (int l=1 ; l<=n-step+1 ; l++) { int r = l + step - 1 ; dp[l][r] = Integer.MAX_VALUE; for (int i=l; i<=r; i++) { int cur = Math.max(dp[l][i-1 ], dp[i+1 ][r]) + i; dp[l][r] = Math.min(cur, dp[l][r]); } } } return dp[1 ][n]; } }
记忆化搜索(用map或者dp前面的数据) + 状态压缩(1~n,且n比较小,那么用一个二进制表示) 有点难度,不过,可以知道有向图找两个节点之间的最长距离
背包问题 1
注意,感觉有些有些题目,跟使用回溯 ,寻找所有的个数。
不过,动态规划,是找个数,规模会大;而回溯的话是找出所有的种类,所以规模会小,因为时间复杂度高。
【动态规划/背包问题】那就从 0-1 背包问题开始讲起吧 …
2
不论是01背包,还是完全背包
会有,恰好 凑成容量j,还是最多不超过 。加一个哨兵机制啊,然后商品下标从1开始。
【动态规划/背包问题】从「最多不超过」到「恰好」,换个角度来理解「背包问题」…
3 时间复杂度。
看dp数组,有多少个状态转移,第一维多少个,第二维多少个,每次状态转移花多久,相乘。(当然,也就是下面的for循环几次,循环里面的时间)
归纳 最多不超过 (01和完全都可),未验证,也可以dp[m+1[n+1],然后dp[0][0]表示第0个什么物品都不取,所以都是0,边界就省去了。是的,然后取nums的时候下标记得是-1。
①二维dp[m][n+1](初始化第0行,即第一个物品)
②dp[m][n+1]
③dp[n+1]
③①01背包由于第i个,依赖于地i-1个j和j-w[i],所以从后往前(这样不会被覆盖)
③②「01 背包将容量维度「从大到小」遍历代表每件物品只能选择一件,而完全背包将容量维度「从小到大」遍历代表每件物品可以选择多次。」
完全背包,使用数学方法,归纳出来的
注意上面,两者一个是本行,一个是上一行
空间复杂度小了,但是时间复杂度肯定是没有变化的
恰好 (01和完全)调整状态定义,多增加一个哨兵0,物品编号从1开始。dp[0][0]=0,其余都是最大值(因为后面是要求最小)。
方便初始化,让dp[0][x]代表不考虑任何物品的情况,这样的话,就不用首先把第一个物品判断掉了。
①二维dp[m+1][n+1](初始化第0行,即第一个物品)
②dp[2 ][n+1]
③dp[n+1],01从后往前,完全从前往后
完全和切好的区别 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 import java.util.Arrays;import java.util.Scanner;public class App { public static void main (String[] args) throws Exception { Scanner scanner = new Scanner (System.in); int n = scanner.nextInt(); int total = scanner.nextInt(); scanner.nextLine(); int [] w = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); int [] v = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); int [][] dp1 = new int [n+1 ][total+1 ]; for (int i = 0 ; i < dp1.length; i++) { Arrays.fill(dp1[i], 0 ); } int [][] dp2 = new int [n+1 ][total+1 ]; for (int i = 0 ; i < dp2.length; i++) { Arrays.fill(dp2[i], -0x3f3f3f3f ); } dp2[0 ][0 ] = 0 ; for (int i = 1 ; i < n + 1 ; i++) { for (int j = 0 ; j < total + 1 ; j++) { dp1[i][j] = Math.max(dp1[i-1 ][j], j >= w[i-1 ] ? dp1[i-1 ][j-w[i-1 ]] + v[i-1 ] : 0 ); dp2[i][j] = Math.max(dp2[i-1 ][j], j >= w[i-1 ] ? dp2[i-1 ][j-w[i-1 ]] + v[i-1 ] : -0x3f3f3f3f ); } } System.out.println("二维数组 少于等于:" + dp1[n][total]); System.out.println("二维数组 正好:" + (dp2[n][total] < 0 ? 0 : dp2[n][total])); int [] dp3 = new int [total+1 ]; dp3[0 ] = 0 ; int [] dp4 = new int [total+1 ]; Arrays.fill(dp4, -0x3f3f3f3f ); dp4[0 ] = 0 ; for (int i = 1 ; i < n + 1 ; i++) { for (int j = total; j >= w[i-1 ]; j--) { dp3[j] = Math.max(dp3[j], dp3[j-w[i-1 ]] + v[i-1 ]); dp4[j] = Math.max(dp4[j], dp4[j-w[i-1 ]] + v[i-1 ]); } } System.out.println("一维数组 少于等于:" + dp3[total]); System.out.println("一维数组 少于等于:" + (dp4[total] < 0 ? 0 : dp4[total])); } }
01 首先哨兵,只要考虑dp[0]边界即可
二维 一维 【动态规划/背包问题】那就从 0-1 背包问题开始讲起吧
从后往前 ,因为二维的递推公式中,每一次依赖的是上一次当前的以及上一次j-nums[i-1]的,所以需要从后往前。
从后往前 ,j开始是总容量,然后**结束是>=nums[i-1]**,而不是0.
由于哨兵,注意每次是nums[i-1]。
1 dp[j] = Math.max(dp[j], dp[j-w[i-1 ]] + v[j-1 ])
完全 首先哨兵,只要考虑dp[0][0]边界即可,其他的是0还是最大值还是什么需要根据题目来。
主要讲的是,优化问题
二维 一维 【宫水三叶の背包问题】站在更高的角度看待一般性的背包问题一维空间优化
一个维度的时候,完全背包考虑还是从前往后 的(因为能够多次选择i,所以前面的被覆盖了也没事,也可以看上面的解析),不需要判断k的那一层了,而且每次加dp[j-coins[i-1]]就可以,注意是i-1,因为哨岗 。
注意,由于j-w[i-1],所以,每一次j从j-w[i-1]开始 到最后totalWeight。
1 dp[j] = Math.max(dp[j], dp[j-w[i-1 ]] + v[j-1 ])
完全背包问题,可以重复使用,但是不同的是,第二维的那个数字j,指的是恰好凑成功的,而不是不超过容量j
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 class Solution { public int numSquares (int n) { int sqrtn = (int )(Math.sqrt(n)); int [][] dp = new int [sqrtn+1 ][n+1 ]; for (int i=0 ; i<=sqrtn; i++) { Arrays.fill(dp[i], 0x3f3f3f3f ); } dp[0 ][0 ] = 0 ; for (int i=1 ; i<=sqrtn; i++) { for (int j=0 ; j<=n; j++) { for (int k=0 ; k*i*i<=j; k++) { if (dp[i-1 ][j-k*i*i] != 0x3f3f3f3f ) { dp[i][j] = Math.min(dp[i][j], dp[i-1 ][j-k*i*i]+k); } } } } return dp[sqrtn][n]; } } class Solution { public int numSquares (int n) { int [] dp = new int [n+1 ]; Arrays.fill(dp, 0x3f3f3f3f ); dp[0 ] = 0 ; for (int i = 1 ; i * i <= n; i++) { for (int j = i * i; j <= n; j++) { dp[j] = Math.min(dp[j-i*i]+1 , dp[j]); } } return dp[n]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 class Solution { public int coinChange (int [] coins, int amount) { int INF = Integer.MAX_VALUE; int coinZhonglei = coins.length; int [][] dp = new int [coinZhonglei+1 ][amount + 1 ]; for (int i=0 ; i<=coinZhonglei; i++) { Arrays.fill(dp[i], INF); } dp[0 ][0 ] = 0 ; for (int i=1 ; i<=coinZhonglei; i++) { int coin = coins[i-1 ]; for (int j=0 ; j<=amount; j++) { for (int k=0 ; k*coin<=j; k++) { if (dp[i-1 ][j-k*coin] != INF) { dp[i][j] = Math.min(dp[i][j], dp[i-1 ][j-k*coin] + k); } } } } return dp[coinZhonglei][amount] == INF ? -1 : dp[coinZhonglei][amount]; } } class Solution { public int coinChange (int [] coins, int amount) { int n = coins.length; int INF = 0x3f3f3f3f ; int [][] dp = new int [n+1 ][amount+1 ]; for (int i = 0 ; i < n + 1 ; i++) { Arrays.fill(dp[i], INF); } dp[0 ][0 ] = 0 ; for (int i = 1 ; i <= n; i++) { for (int j = 0 ; j <= amount; j++) { for (int k = 0 ; k * coins[i-1 ] <= j; k++) { dp[i][j] = Math.min(dp[i-1 ][j-k*coins[i-1 ]] + k, dp[i][j]); } } } return dp[n][amount] == INF ? -1 : dp[n][amount]; } }
宫水,恰好完全背包,以及优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { public int change (int amount, int [] coins) { int n = coins.length; int [][] dp = new int [n + 1 ][amount + 1 ]; dp[0 ][0 ] = 1 ; for (int i = 1 ; i <= coins.length; i++) { for (int j = 0 ; j <= amount; j++) { for (int k = 0 ; k * coins[i-1 ] <= j; k++) { dp[i][j] += dp[i-1 ][j-k*coins[i-1 ]]; } } } return dp[n][amount]; } } class Solution { public int change (int amount, int [] coins) { int n = coins.length; int [] dp = new int [amount+1 ]; dp[0 ] = 1 ; for (int i = 1 ; i <= n; i++) { for (int j = coins[i-1 ]; j <= amount; j++) { dp[j] += dp[j-coins[i-1 ]]; } } return dp[amount]; } }
状态压缩dp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class Solution { public int minStickers (String[] stickers, String target) { int tLen = target.length(); int mask = 1 << tLen; int [] dp = new int [mask]; Arrays.fill(dp, Integer.MAX_VALUE); dp[0 ] = 0 ; for (int state = 0 ; state < mask; state++) { if (dp[state] == Integer.MAX_VALUE) { continue ; } for (String sticker: stickers) { int nextState = state; for (int i = 0 ; i < sticker.length(); i++) { for (int j = 0 ; j < target.length(); j++) { if (target.charAt(j) == sticker.charAt(i) && ((1 << j) & nextState) == 0 ) { nextState |= (1 << j); break ; } } } dp[nextState] = Math.min(dp[state] + 1 , dp[nextState]); } } return dp[mask - 1 ] == Integer.MAX_VALUE ? -1 : dp[mask - 1 ]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 class Solution { public int countArrangement (int n) { int mask = 1 << n; int [][] dp = new int [n + 1 ][mask]; dp[0 ][0 ] = 1 ; for (int i = 1 ; i <= n; i++) { for (int state = 0 ; state < mask; state++) { for (int k = 1 ; k <= n; k++) { if (!(k % i == 0 || i % k == 0 )) { continue ; } if (((state >> (k-1 )) & 1 ) == 0 ) { continue ; } dp[i][state] += dp[i-1 ][state & ~(1 << (k-1 ))]; } } } return dp[n][mask-1 ]; } }
单调栈 一但要求下一个更大的元素,就是用单调栈解,力扣题库相似的题目都是这个解法。
注意,单调栈从前往后 和 从后往前,栈里面最后的元素不一样,而且,while里面的内容也有点区别。
注意下面496和503的两种写法,都是找下一个最大的,一个从前往后找,一个从后往前找,但是考虑的逻辑就不一样了。
从前往后的话,若找下一个大的,那么从栈底到栈顶也是从大到小(一样),但是ans给值情况从前往后在while里面,从后往前在while下面,while下面的话因为每个for存一个是全的,但是需要考虑栈底没有元素的时候存什么;而从前往后的再while里面所以存的时候肯定栈里面有数据而且ans不能保存存完全,所以最开始的时候需要给数组一个全部的初始值。
自己总结的规律 :①不论是从左往右还是从右往左,不论是求比当前值小的左边第一个,还是比当前值小的右边的第一个,如果是小的,那么栈里面从底部到上面就是从小到大 的,放入的时候如果栈最上面的比当前的大,那么就拿出来。
然后再考虑,是在while里面放呢,还是在while的外面for的里面放。
其实这个也有规律,②要求比当前值小的左边的,那么从左往右就是放在while外面for里面 ,当前值小的右边的第一个,那么从右边往前。③注意等号问题
所以以后分两步:①要求小的,那么单调栈从下到上是从小到大;②求当前值的左边第一个小的,那么从左往右,就可以一个个看。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public int [] nextGreaterElement(int [] nums1, int [] nums2) { Deque<Integer> stack = new ArrayDeque <>(); Map<Integer, Integer> map = new HashMap <>(); for (int i = nums2.length-1 ; i >= 0 ; i--) { int num = nums2[i]; while (!stack.isEmpty() && stack.peek() <= num) { stack.pop(); } map.put(num, stack.isEmpty() ? -1 : stack.peek()); stack.push(num); } int [] ans = new int [nums1.length]; for (int i = 0 ; i < nums1.length; i++) { ans[i] = map.get(nums1[i]); } return ans; } }
数组中无重复元素的话,可以map存储值,但是此处只能存下标。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { public int [] nextGreaterElements(int [] nums) { Deque<Integer> stack = new ArrayDeque <>(); int [] ans = new int [nums.length]; Arrays.fill(ans, -1 ); int n = nums.length; for (int i = 0 ; i < 2 * n - 1 ; i++) { int num = nums[i % n]; while (!stack.isEmpty() && nums[stack.peek()] < num) { ans[stack.pop()] = nums[i % n]; } stack.push(i % n); } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public boolean find132pattern (int [] nums) { Deque<Integer> stack = new ArrayDeque <>(); int numsk = Integer.MIN_VALUE; for (int i = nums.length-1 ; i >= 0 ; i--) { if (nums[i] < numsk) { return true ; } while (!stack.isEmpty() && stack.peek() < nums[i]) { numsk = Math.max(numsk, stack.pop()); } stack.push(nums[i]); } return false ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class Solution { public long subArrayRanges (int [] nums) { Deque<Integer> minStack = new ArrayDeque <>(); Deque<Integer> maxStack = new ArrayDeque <>(); int n = nums.length; int [] minLeft = new int [n]; int [] maxLeft = new int [n]; int [] minRight = new int [n]; int [] maxRight = new int [n]; for (int i = 0 ; i < nums.length; i++) { int num = nums[i]; while (!minStack.isEmpty() && nums[minStack.peek()] > num) { minStack.pop(); } minLeft[i] = minStack.isEmpty() ? -1 : minStack.peek(); minStack.push(i); while (!maxStack.isEmpty() && nums[maxStack.peek()] <= num) { maxStack.pop(); } maxLeft[i] = maxStack.isEmpty() ? -1 : maxStack.peek(); maxStack.push(i); } minStack.clear(); maxStack.clear(); for (int i = nums.length-1 ; i >= 0 ; i--) { int num = nums[i]; while (!minStack.isEmpty() && nums[minStack.peek()] >= num) { minStack.pop(); } minRight[i] = minStack.isEmpty() ? n : minStack.peek(); minStack.push(i); while (!maxStack.isEmpty() && nums[maxStack.peek()] < num) { maxStack.pop(); } maxRight[i] = maxStack.isEmpty() ? n : maxStack.peek(); maxStack.push(i); } long ans = 0 ; for (int i = 0 ; i < n; i++) { ans += (long ) (maxRight[i] - i) * (i - maxLeft[i]) * nums[i]; ans -= (long ) (minRight[i] - i) * (i - minLeft[i]) * nums[i]; } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public int trap (int [] height) { Deque<Integer> stack = new ArrayDeque <>(); int ans = 0 ; for (int i = 0 ; i < height.length; i++) { while (!stack.isEmpty() && height[i] > height[stack.peek()]) { int top = stack.pop(); if (stack.isEmpty()) { break ; } int left = stack.peek(); int length = Math.min(height[left], height[i]) - height[top]; int width = i - left - 1 ; ans += width * length; } stack.push(i); } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 class Solution { public int largestRectangleArea (int [] heights) { Deque<Integer> stack = new ArrayDeque <Integer>(); int n = heights.length; int [] left = new int [n]; int [] right = new int [n]; for (int i = 0 ; i < n; i++) { while (!stack.isEmpty() && heights[stack.peekLast()] >= heights[i]) { stack.pollLast(); } left[i] = stack.isEmpty() ? -1 : stack.peekLast(); stack.offerLast(i); } stack.clear(); for (int i = n-1 ; i >= 0 ; i--) { while (!stack.isEmpty() && heights[stack.peekLast()] >= heights[i]) { stack.pollLast(); } right[i] = stack.isEmpty() ? n : stack.peekLast(); stack.offerLast(i); } int ans = 0 ; for (int i = 0 ; i < n; i++) { ans = Math.max(ans, heights[i] * (right[i] - left[i] - 1 )); } return ans; } } class Solution { public int largestRectangleArea (int [] heights) { Deque<Integer> stack = new ArrayDeque <Integer>(); int n = heights.length; int [] left = new int [n]; int [] right = new int [n]; Arrays.fill(right, n); for (int i = 0 ; i < n; i++) { while (!stack.isEmpty() && heights[stack.peekLast()] >= heights[i]) { right[stack.peekLast()] = i; stack.pollLast(); } left[i] = stack.isEmpty() ? -1 : stack.peekLast(); stack.offerLast(i); } int ans = 0 ; for (int i = 0 ; i < n; i++) { ans = Math.max(ans, heights[i] * (right[i] - left[i] - 1 )); } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Solution { public int maximalRectangle (char [][] matrix) { int row = matrix.length; int col = matrix[0 ].length; int ans = 0 ; if (row == 0 ) { return ans; } int [][] heightss = new int [row][col]; for (int i = 0 ; i < row; i++) { for (int j = 0 ; j < col; j++) { if (matrix[i][j] == '1' ) { heightss[i][j] += i > 0 ? heightss[i-1 ][j] + 1 : 1 ; } else { heightss[i][j] = 0 ; } } } for (int [] heights: heightss) { Deque<Integer> stack = new ArrayDeque <Integer>(); int [] right = new int [col]; int [] left = new int [col]; for (int i = 0 ; i < col; i++) { while (!stack.isEmpty() && heights[stack.peekLast()] >= heights[i]) { stack.pollLast(); } left[i] = stack.isEmpty() ? -1 : stack.peekLast(); stack.offerLast(i); } stack.clear(); for (int i = col - 1 ; i >= 0 ; i--) { while (!stack.isEmpty() && heights[stack.peekLast()] >= heights[i]) { stack.pollLast(); } right[i] = stack.isEmpty() ? col : stack.peekLast(); stack.offerLast(i); } for (int i = 0 ; i < col; i++) { ans = Math.max(ans, (right[i] - left[i] - 1 ) * heights[i]); } } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { public String removeKdigits (String num, int k) { Deque<Character> stack = new ArrayDeque <>(); char [] nums = num.toCharArray(); int n = nums.length; int count = 0 ; for (int i = 0 ; i < n; i++) { while (!stack.isEmpty() && stack.peekLast() > nums[i] && count < k) { stack.pollLast(); count++; } if (stack.isEmpty() && nums[i] == '0' ) { continue ; } stack.offerLast(nums[i]); } if (count < k) { while (count < k) { stack.pollLast(); count++; } } if (stack.isEmpty()) { return "0" ; } StringBuilder sb = new StringBuilder (); while (!stack.isEmpty()) { sb.append(stack.pollLast()); } return sb.reverse().toString(); } }
栈 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution { public boolean checkValidString (String s) { Deque<Integer> stack1 = new ArrayDeque <>(); Deque<Integer> stack2 = new ArrayDeque <>(); char [] chars = s.toCharArray(); for (int i=0 ; i<chars.length; i++) { char c = chars[i]; if (c == '(' ) { stack1.offerLast(i); } else if (c == '*' ) { stack2.offerLast(i); } else { if (!stack1.isEmpty()) { stack1.pollLast(); } else if (!stack2.isEmpty()) { stack2.pollLast(); } else { return false ; } } } while (!stack1.isEmpty()) { int leftIndex = stack1.pollLast(); if (stack2.isEmpty()) { return false ; } int rightIndex = stack2.pollLast(); if (leftIndex >= rightIndex) { return false ; } } return true ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public String removeStars (String s) { char [] chars = s.toCharArray(); Deque<Character> stack = new ArrayDeque <>(); for (char c: chars) { if (c == '*' ) { stack.pollLast(); } else { stack.offerLast(c); } } StringBuilder sb = new StringBuilder (); while (!stack.isEmpty()) { sb.append(stack.pollFirst()); } return sb.toString(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution { public String reverseParentheses (String s) { char [] chars = s.toCharArray(); Deque<Character> stack = new ArrayDeque <>(); Deque<Character> queue = new ArrayDeque <>(); for (int i = 0 ; i < chars.length; i++) { if (chars[i] == ')' ) { while (stack.peekLast() != '(' ) { queue.offerLast(stack.pollLast()); } stack.pollLast(); while (!queue.isEmpty()) { stack.offerLast(queue.pollFirst()); } } else { stack.offerLast(chars[i]); } } StringBuilder sb = new StringBuilder (); while (!stack.isEmpty()) { sb.append(stack.pollFirst()); } return sb.toString(); } }
BFS 对于层序遍历,使用BFS
对于层序遍历的序列化和非序列化,使用BFS;当然DFS先序遍历的,也可以。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 public class Codec { TreeNode emptyNode = new TreeNode (-2000 ); public String serialize (TreeNode root) { if (root == null ) { return "" ; } StringBuffer str = new StringBuffer (); Deque<TreeNode> queue = new ArrayDeque <>(); queue.offerLast(root); while (!queue.isEmpty()) { TreeNode node = queue.pollFirst(); if (node == emptyNode) { str.append("null," ); continue ; } str.append(String.valueOf(node.val) + "," ); queue.offerLast(node.left == null ? emptyNode : node.left); queue.offerLast(node.right == null ? emptyNode : node.right); } str.deleteCharAt(str.length() - 1 ); return str.toString(); } public TreeNode deserialize (String data) { if (data.equals("" )) { return null ; } String[] strs = data.split("," ); Deque<TreeNode> queue = new ArrayDeque <TreeNode>(); TreeNode root = new TreeNode (Integer.parseInt(strs[0 ])); queue.offerLast(root); for (int i=1 ; i<strs.length; i += 2 ) { TreeNode node = queue.pollFirst(); if (!strs[i].equals("null" )) { TreeNode leftNode = new TreeNode (Integer.parseInt(strs[i])); node.left = leftNode; queue.offerLast(leftNode); } if (!strs[i+1 ].equals("null" )) { TreeNode rightNode = new TreeNode (Integer.parseInt(strs[i+1 ])); node.right = rightNode; queue.offerLast(rightNode); } } return root; } }
完全二叉树序列化反序列化模版归纳 leetcode中的模版方法中,树直接给TreeNode的,但是如果机试输入的是二叉树的层序遍历,那么需要自己反序列化成树。
注意,下面的序列化和反序列化,是按照完全二叉树的层序遍历来的。
即:序列化时,n层2^n-1个,null全部算进去的;不过反序列化时,除了最后一层,上面层的都是满的,上面层就算下面两个都是null的null,也要写,这是与上面那个序列化与反序列化的区别,上面那个在2997中不会超内存,这个在297中会。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 package leetcode.editor.cn;import java.util.*;public class TemplateTreeDeserialize { public static void main (String[] args) { TemplateTreeDeserialize mySolution = new TemplateTreeDeserialize (); Solution solution = mySolution.new Solution (); TreeUtil treeUtil = mySolution.new TreeUtil (); System.out.println(solution.solve(treeUtil.deserialize("xxx,x,xxx,null,x" ))); } public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(int val) { this .val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this .val = val; this .left = left; this .right = right; } } public final class TreeUtil { public int getHeight (TreeNode node, int height) { if (node == null ) { return height; } int leftHeight = getHeight(node.left, height + 1 ); int rightHeight = getHeight(node.right, height + 1 ); return Math.max(leftHeight, rightHeight); } TreeNode emptyNode = new TreeNode (-2000 ); public TreeNode deserialize (String data) { if (data.equals("" )) { return null ; } String[] strs = data.split("," ); TreeNode[] nodes = new TreeNode [strs.length]; for (int i = 0 ; i < strs.length; i++) { nodes[i] = strs[i].equals("null" ) ? emptyNode : new TreeNode (Integer.parseInt(strs[i])); } for (int i = 0 ; i < nodes.length / 2 ; i++) { if (nodes[i] == emptyNode) { continue ; } int leftIndex = 2 * i + 1 ; int rightIndex = 2 * i + 2 ; if (nodes[leftIndex] == emptyNode) { nodes[i].left = null ; } else { nodes[i].left = nodes[leftIndex]; } if (rightIndex < nodes.length) { if (nodes[rightIndex] == emptyNode) { nodes[i].right = null ; } else { nodes[i].right = nodes[rightIndex]; } } } return nodes[0 ]; } public String serialize (TreeNode root) { if (root == null ) { return "" ; } StringBuilder str = new StringBuilder (); Deque<TreeNode> queue = new ArrayDeque <>(); int allNum = (int ) Math.pow(2 , getHeight(root, 0 )) - 1 , count = 0 ; queue.offerLast(root); while (!queue.isEmpty()) { TreeNode node = queue.pollFirst(); if (node == emptyNode) { str.append("null," ); } else { str.append(node.val + "," ); } if (++count >= allNum) { break ; } queue.offerLast(node.left == null ? emptyNode : node.left); queue.offerLast(node.right == null ? emptyNode : node.right); } str.deleteCharAt(str.length() - 1 ); return str.toString(); } } class Solution { public int solve (TreeNode root) { return root.val; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public class Codec { public String serialize (TreeNode root) { String a = serialize1(root); System.out.println(a); return a; } public String serialize1 (TreeNode node) { if (node == null ) { return "null" ; } return node.val + "," + serialize1(node.left) + "," + serialize1(node.right); } public TreeNode deserialize (String data) { String[] datas = data.split("," ); List<String> list = new ArrayList (Arrays.asList(datas)); return deserialize1(list); } public TreeNode deserialize1 (List<String> list) { if (list.get(0 ).equals("null" )) { list.remove(0 ); return null ; } TreeNode node = new TreeNode (Integer.valueOf(list.get(0 ))); list.remove(0 ); node.left = deserialize1(list); node.right = deserialize1(list); return node; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 package leetcode.editor.cn;import com.sun.source.tree.Tree;import java.util.*;public class P230KthSmallestElementInABst { public static void main (String[] args) { P230KthSmallestElementInABst mySolution = new P230KthSmallestElementInABst (); Solution solution = mySolution.new Solution (); TreeUtil treeUtil = mySolution.new TreeUtil (); System.out.println(solution.kthSmallest(treeUtil.deserialize("3,1,4,null,2" ), 1 )); } class Solution { public int kthSmallest (TreeNode root, int k) { int curIndex = 0 ; Deque<TreeNode> stack = new ArrayDeque <>(); while (root != null || !stack.isEmpty()) { while (root != null ) { stack.offerLast(root); root = root.left; } TreeNode node = stack.pollLast(); if (++curIndex == k) { return node.val; } root = node.right; } return -1 ; } } public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(int val) { this .val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this .val = val; this .left = left; this .right = right; } } public final class TreeUtil { public int getHeight (TreeNode node, int height) { if (node == null ) { return height; } int leftHeight = getHeight(node.left, height + 1 ); int rightHeight = getHeight(node.right, height + 1 ); return Math.max(leftHeight, rightHeight); } TreeNode emptyNode = new TreeNode (-2000 ); public TreeNode deserialize (String data) { if (data.equals("" )) { return null ; } String[] strs = data.split("," ); TreeNode[] nodes = new TreeNode [strs.length]; for (int i = 0 ; i < strs.length; i++) { nodes[i] = strs[i].equals("null" ) ? emptyNode : new TreeNode (Integer.parseInt(strs[i])); } for (int i = 0 ; i < nodes.length / 2 ; i++) { if (nodes[i] == emptyNode) { continue ; } int leftIndex = 2 * i + 1 ; int rightIndex = 2 * i + 2 ; if (nodes[leftIndex] == emptyNode) { nodes[i].left = null ; } else { nodes[i].left = nodes[leftIndex]; } if (rightIndex < nodes.length) { if (nodes[rightIndex] == emptyNode) { nodes[i].right = null ; } else { nodes[i].right = nodes[rightIndex]; } } } return nodes[0 ]; } public String serialize (TreeNode root) { if (root == null ) { return "" ; } StringBuilder str = new StringBuilder (); Deque<TreeNode> queue = new ArrayDeque <>(); int allNum = (int ) Math.pow(2 , getHeight(root, 0 )) - 1 , count = 0 ; queue.offerLast(root); while (!queue.isEmpty()) { TreeNode node = queue.pollFirst(); if (node == emptyNode) { } else { str.append(node.val + "," ); } if (++count >= allNum) { break ; } queue.offerLast(node.left == null ? emptyNode : node.left); queue.offerLast(node.right == null ? emptyNode : node.right); } str.deleteCharAt(str.length() - 1 ); return str.toString(); } } }
注意第二个算法中,用了一个hashmap,记录n到这个数字num的当最小次数,可以减少重复次数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 class Solution { public int integerReplacement (int n) { if (n == 1 ) { return 0 ; } Deque<Long> queue = new ArrayDeque <Long>(); int minNum = 0 ; queue.offerLast((long )n); while (!queue.isEmpty()) { minNum += 1 ; int size = queue.size(); for (int i=0 ; i<size; i++) { long num = queue.pollFirst(); if (num % 2 == 0 ) { num /= 2 ; if (num == 1 ) { return minNum; } else { queue.offerLast(num); } } else { if (num - 1 == 1 ) { return minNum; } else { queue.offerLast(num - 1 ); } if (num + 1 == 1 ) { return minNum; } else { queue.offerLast(num + 1 ); } } } } return minNum; } } class Solution { public int integerReplacement (int n) { if (n == 1 ) return 0 ; Map<Long, Integer> map = new HashMap <>(); Deque<Long> d = new ArrayDeque <>(); d.addLast(n * 1L ); map.put(n * 1L , 0 ); while (!d.isEmpty()) { long t = d.pollFirst(); int step = map.get(t); long [] ns = t % 2 == 0 ? new long []{t / 2 } : new long []{t + 1 , t - 1 }; for (long x : ns) { if (x == 1 ) return step + 1 ; if (!map.containsKey(x)) { map.put(x, step + 1 ); d.addLast(x); } } } return -1 ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public List<String> letterCombinations (String digits) { Deque<String> queue = new ArrayDeque <String>(); if (digits.length() == 0 ) { return new ArrayList <String>(); } char [][] mapping = new char [][]{{'a' , 'b' , 'c' }, {'d' , 'e' , 'f' }, {'g' , 'h' , 'i' }, {'j' , 'k' , 'l' }, {'m' , 'n' , 'o' }, {'p' , 'q' , 'r' , 's' }, {'t' , 'u' , 'v' }, {'w' , 'x' , 'y' , 'z' }}; for (char c: mapping[digits.charAt(0 ) - '2' ]) { queue.offerLast("" + c); } for (int i=1 ; i<digits.length(); i++) { int size = queue.size(); for (int j=0 ; j<size; j++) { String temp = queue.pollFirst(); for (char c: mapping[digits.charAt(i) - '2' ]) { queue.offerLast(temp + c); } } } List<String> ans = new ArrayList <>(); while (!queue.isEmpty()) { ans.add(queue.pollFirst()); } return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class Solution { public int findBottomLeftValue (TreeNode root) { TreeNode ansNode = null ; Deque<TreeNode> queue = new ArrayDeque <>(); queue.offerLast(root); while (!queue.isEmpty()) { ansNode = queue.peekFirst(); int size = queue.size(); for (int i=0 ; i<size; i++) { TreeNode temp = queue.pollFirst(); if (temp.left != null ) { queue.offerLast(temp.left); } if (temp.right != null ) { queue.offerLast(temp.right); } } } return ansNode.val; } } class Solution { public int findBottomLeftValue (TreeNode root) { int ret = 0 ; Queue<TreeNode> queue = new ArrayDeque <TreeNode>(); queue.offer(root); while (!queue.isEmpty()) { TreeNode p = queue.poll(); if (p.right != null ) { queue.offer(p.right); } if (p.left != null ) { queue.offer(p.left); } ret = p.val; } return ret; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public boolean makesquare (int [] matchsticks) { int sum = Arrays.stream(matchsticks).sum(); if (sum % 4 != 0 ) { return false ; } matchsticks = Arrays.stream(matchsticks).boxed().sorted((a, b) -> b - a).mapToInt(Integer::valueOf).toArray(); return dfsTrace(new int [4 ], sum / 4 , 0 , matchsticks.length, matchsticks); } public boolean dfsTrace (int [] bucks, int par, int curIndex, int n, int [] matchsticks) { if (curIndex == n) { return true ; } for (int i = 0 ; i < bucks.length; i++) { if (bucks[i] + matchsticks[curIndex] <= par) { bucks[i] += matchsticks[curIndex]; if (dfsTrace(bucks, par, curIndex + 1 , n, matchsticks)) { return true ; } bucks[i] -= matchsticks[curIndex]; } } return false ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class Solution { public Node cloneGraph (Node node) { if (node == null ) { return null ; } Map<Node, Node> map = new HashMap <>(); Node cNode = new Node (node.val, new ArrayList <>()); map.put(node, cNode); Deque<Node> queue = new ArrayDeque <>(); queue.add(node); while (!queue.isEmpty()) { Node temp = queue.pollFirst(); Node copyNode = map.get(temp); for (Node nei: temp.neighbors) { if (map.containsKey(nei)) { copyNode.neighbors.add(map.get(nei)); } else { Node copyNeiNode = new Node (nei.val, new ArrayList <>()); copyNode.neighbors.add(copyNeiNode); map.put(nei, copyNeiNode); queue.offerLast(nei); } } } return cNode; } }
多源BFS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 class Solution { int m, n; public List<List<Integer>> pacificAtlantic (int [][] heights) { m = heights.length; n = heights[0 ].length; boolean [][] pac = new boolean [m][n]; boolean [][] atl = new boolean [m][n]; for (int i = 0 ; i < m; i++) { pac[i][0 ] = true ; bfs(heights, pac, new int []{i, 0 }); atl[i][n-1 ] = true ; bfs(heights, atl, new int []{i, n-1 }); } for (int i = 0 ; i < n; i++) { pac[0 ][i] = true ; bfs(heights, pac, new int []{0 , i}); atl[m-1 ][i] = true ; bfs(heights, atl, new int []{m-1 , i}); } List<List<Integer>> list = new ArrayList <>(); for (int i = 0 ; i < m; i++) { for (int j = 0 ; j < n; j++) { if (pac[i][j] && atl[i][j]) { List<Integer> pos = new ArrayList <>(); pos.add(i); pos.add(j); list.add(pos); } } } return list; } int [][] dir = new int [][]{{0 , 1 }, {0 , -1 }, {1 , 0 }, {-1 , 0 }}; public void bfs (int [][] heights, boolean [][] ocean, int [] pos) { Deque<int []> queue = new ArrayDeque <>(); queue.offerLast(pos); while (!queue.isEmpty()) { int [] cur = queue.pollFirst(); int x = cur[0 ], y = cur[1 ]; for (int i = 0 ; i < 4 ; i++) { int newX = x + dir[i][0 ]; int newY = y + dir[i][1 ]; if (newX >= 0 && newX<m && newY >= 0 && newY < n && heights[newX][newY] >= heights[x][y] && !ocean[newX][newY]) { ocean[newX][newY] = true ; queue.offerLast(new int []{newX, newY}); } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 class Solution { int [][] grid; int m, n; int [][] dirs = new int [][]{{1 , 0 }, {-1 , 0 }, {0 , 1 }, {0 , -1 }}; public int numEnclaves (int [][] grid) { this .grid = grid; this .m = grid.length; this .n = grid[0 ].length; for (int i=0 ; i<m; i++) { if (grid[i][0 ] == 1 ) { bfs(new int []{i, 0 }); } if (grid[i][n-1 ] == 1 ) { bfs(new int []{i, n-1 }); } } for (int i=0 ; i<n; i++) { if (grid[0 ][i] == 1 ) { bfs(new int []{0 , i}); } if (grid[m-1 ][i] == 1 ) { bfs(new int []{m-1 , i}); } } int ans = 0 ; for (int i = 0 ; i < m; i++) { for (int j = 0 ; j < n; j++) { if (grid[i][j] == 1 ) { ans += 1 ; } } } return ans; } public void bfs (int [] pos) { Deque<int []> queue = new ArrayDeque <>(); grid[pos[0 ]][pos[1 ]] = 0 ; queue.offerLast(pos); while (!queue.isEmpty()) { int [] newPos = queue.pollFirst(); int x = newPos[0 ], y = newPos[1 ]; for (int [] dir: dirs) { int newX = x + dir[0 ]; int newY = y + dir[1 ]; if (newX >= 0 && newX < m && newY >= 0 && newY < n && grid[newX][newY] == 1 ) { grid[newX][newY] = 0 ; queue.offerLast(new int []{newX, newY}); } } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { int [][] dirs = {{-1 , 0 }, {1 , 0 }, {0 , -1 }, {0 , 1 }}; public int [][] highestPeak(int [][] isWater) { int m = isWater.length, n = isWater[0 ].length; int [][] ans = new int [m][n]; for (int i = 0 ; i < m; ++i) { Arrays.fill(ans[i], -1 ); } Queue<int []> queue = new ArrayDeque <int []>(); for (int i = 0 ; i < m; ++i) { for (int j = 0 ; j < n; ++j) { if (isWater[i][j] == 1 ) { ans[i][j] = 0 ; queue.offer(new int []{i, j}); } } } while (!queue.isEmpty()) { int [] p = queue.poll(); for (int [] dir : dirs) { int x = p[0 ] + dir[0 ], y = p[1 ] + dir[1 ]; if (0 <= x && x < m && 0 <= y && y < n && ans[x][y] == -1 ) { ans[x][y] = ans[p[0 ]][p[1 ]] + 1 ; queue.offer(new int []{x, y}); } } } return ans; } }
麻麻的,官方题解这样做也超时。。。🙈
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 class Solution { int [][] grid; int m, n; int [][] dirs = new int [][]{{1 , 0 }, {-1 , 0 }, {0 , 1 }, {0 , -1 }}; public int maxDistance (int [][] grid) { m = grid.length; n = grid[0 ].length; this .grid = grid; int ans = -1 ; for (int i=0 ; i<m; i++) { for (int j=0 ; j<n; j++) { if (grid[i][j] == 0 ) { ans = Math.max(bfs(new int []{i, j}), ans); } } } return ans; } public int bfs (int [] pos) { boolean [][] vis = new boolean [m][n]; Deque<int []> queue = new ArrayDeque <>(); queue.offerLast(pos); vis[pos[0 ]][pos[1 ]] = true ; int dis = 0 ; while (!queue.isEmpty()) { dis += 1 ; int size = queue.size(); for (int i=0 ; i<size; i++) { int [] newPos = queue.pollFirst(); int x = newPos[0 ]; int y = newPos[1 ]; for (int [] dir: dirs) { int newX = x + dir[0 ]; int newY = y + dir[1 ]; if (newX >= 0 && newX < m && newY >= 0 && newY < n && !vis[newX][newY]) { queue.offerLast(new int []{newX, newY}); vis[newX][newY] = true ; if (grid[newX][newY] == 1 ) { return dis; } } } } } return -1 ; } }
DFS 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public class Codec { public String serialize (TreeNode root) { List<String> list = new ArrayList <>(); dfs(root, list); System.out.println(list.toString()); return list.toString(); } public void dfs (TreeNode node, List<String> list) { if (node == null ) { list.add("null" ); return ; } list.add(String.valueOf(node.val)); dfs(node.left, list); dfs(node.right, list); } public TreeNode deserialize (String data) { String a = data.substring(1 , data.length()-1 ); String[] strs = a.split(", " ); List<String> list = new ArrayList <String>(Arrays.asList(strs)); System.out.println(list.get(0 )); return DeserializeDfs(list); } public TreeNode DeserializeDfs (List<String> list) { if (list.get(0 ).equals("null" )) { list.remove(0 ); return null ; } TreeNode node = new TreeNode (Integer.parseInt(list.get(0 ))); list.remove(0 ); node.left = DeserializeDfs(list); node.right = DeserializeDfs(list); return node; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { Map<String, Integer> count; List<TreeNode> ans; public List<TreeNode> findDuplicateSubtrees (TreeNode root) { count = new HashMap (); ans = new ArrayList (); collect(root); return ans; } public String collect (TreeNode node) { if (node == null ) return "#" ; String serial = node.val + "," + collect(node.left) + "," + collect(node.right); count.put(serial, count.getOrDefault(serial, 0 ) + 1 ); if (count.get(serial) == 2 ) ans.add(node); return serial; } }
寻找完全相同的最大高度的子树 在一棵二叉树中找出完全相同的两颗子树()子树层数>=2,若存在多棵,返回层数最大的,不存在返回-1
未验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 package leetcode.editor.cn;import java.util.*;public class 寻找完全相同的子树 { public static void main (String args[]) { 寻找完全相同的子树 mySolution = new 寻找完全相同的子树(); Solution solution = mySolution.new Solution (); TreeUtil treeUtil = mySolution.new TreeUtil (); System.out.println(solution.findMaxDepthTree(treeUtil.deserialize("1,4,3,1,null,2,null,null,null,null,null,1,null,null,null" ))); } public class Solution { Map<String, Integer> map; int maxDepth = 1 ; TreeNode nullNode = new TreeNode (-2000 ); TreeNode ans = nullNode; public String findMaxDepthTree (TreeNode root) { map = new HashMap <>(); dfs(root); if (nullNode == ans) { return "-1" ; } return new TreeUtil ().serialize(ans); } public String dfs (TreeNode node) { if (node == null ) { return "null" ; } String serial = node.val + "," + dfs(node.left) + "," + dfs(node.right); map.put(serial, map.getOrDefault(serial, 0 ) + 1 ); if (map.get(serial) >= 2 ) { int height = new TreeUtil ().getHeight(node, 0 ); if (maxDepth < height) { maxDepth = height; ans = node; } } return serial; } } public class TreeNode { int val; TreeNode left; TreeNode right; public TreeNode (int val) { this .val = val; } public TreeNode () { } } public final class TreeUtil { public int getHeight (TreeNode node, int height) { if (node == null ) { return height; } int leftHeight = getHeight(node.left, height + 1 ); int rightHeight = getHeight(node.right, height + 1 ); return Math.max(leftHeight, rightHeight); } TreeNode emptyNode = new TreeNode (-2000 ); public TreeNode deserialize (String data) { if (data.equals("" )) { return null ; } String[] strs = data.split("," ); TreeNode[] nodes = new TreeNode [strs.length]; for (int i = 0 ; i < strs.length; i++) { nodes[i] = strs[i].equals("null" ) ? emptyNode : new TreeNode (Integer.parseInt(strs[i])); } for (int i = 0 ; i < nodes.length / 2 ; i++) { if (nodes[i] == emptyNode) { continue ; } int leftIndex = 2 * i + 1 ; int rightIndex = 2 * i + 2 ; if (nodes[leftIndex] == emptyNode) { nodes[i].left = null ; } else { nodes[i].left = nodes[leftIndex]; } if (rightIndex < nodes.length) { if (nodes[rightIndex] == emptyNode) { nodes[i].right = null ; } else { nodes[i].right = nodes[rightIndex]; } } } return nodes[0 ]; } public String serialize (TreeNode root) { if (root == null ) { return "" ; } StringBuilder str = new StringBuilder (); Deque<TreeNode> queue = new ArrayDeque <>(); int allNum = (int ) Math.pow(2 , getHeight(root, 0 )) - 1 , count = 0 ; queue.offerLast(root); while (!queue.isEmpty()) { TreeNode node = queue.pollFirst(); if (node == emptyNode) { } else { str.append(node.val + "," ); } if (++count >= allNum) { break ; } queue.offerLast(node.left == null ? emptyNode : node.left); queue.offerLast(node.right == null ? emptyNode : node.right); } str.deleteCharAt(str.length() - 1 ); return str.toString(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 package leetcode.editor.cn;import java.util.*;public class P965UnivaluedBinaryTree { public static void main (String[] args) { Solution solution = new P965UnivaluedBinaryTree ().new Solution (); TreeUtil treeUtil = new P965UnivaluedBinaryTree ().new TreeUtil (); System.out.println(solution.isUnivalTree(treeUtil.deserialize("2,2,2,5,2" ))); } class Solution { int val = 0 ; public boolean isUnivalTree (TreeNode root) { val = root.val; return dfs(root); } public boolean dfs (TreeNode node) { if (node == null ) { return true ; } if (node.val != val) { return false ; } return dfs(node.left) && dfs(node.right); } } public class TreeNode { int val; TreeNode left; TreeNode right; TreeNode() {} TreeNode(int val) { this .val = val; } TreeNode(int val, TreeNode left, TreeNode right) { this .val = val; this .left = left; this .right = right; } } public final class TreeUtil { public int getHeight (TreeNode node, int height) { if (node == null ) { return height; } int leftHeight = getHeight(node.left, height + 1 ); int rightHeight = getHeight(node.right, height + 1 ); return Math.max(leftHeight, rightHeight); } TreeNode emptyNode = new TreeNode (-2000 ); public TreeNode deserialize (String data) { if (data.equals("" )) { return null ; } String[] strs = data.split("," ); TreeNode[] nodes = new TreeNode [strs.length]; for (int i = 0 ; i < strs.length; i++) { nodes[i] = strs[i].equals("null" ) ? emptyNode : new TreeNode (Integer.parseInt(strs[i])); } for (int i = 0 ; i < nodes.length / 2 ; i++) { if (nodes[i] == emptyNode) { continue ; } int leftIndex = 2 * i + 1 ; int rightIndex = 2 * i + 2 ; if (nodes[leftIndex] == emptyNode) { nodes[i].left = null ; } else { nodes[i].left = nodes[leftIndex]; } if (rightIndex < nodes.length) { if (nodes[rightIndex] == emptyNode) { nodes[i].right = null ; } else { nodes[i].right = nodes[rightIndex]; } } } return nodes[0 ]; } public String serialize (TreeNode root) { if (root == null ) { return "" ; } StringBuilder str = new StringBuilder (); Deque<TreeNode> queue = new ArrayDeque <>(); int allNum = (int ) Math.pow(2 , getHeight(root, 0 )) - 1 , count = 0 ; queue.offerLast(root); while (!queue.isEmpty()) { TreeNode node = queue.pollFirst(); if (node == emptyNode) { } else { str.append(node.val + "," ); } if (++count >= allNum) { break ; } queue.offerLast(node.left == null ? emptyNode : node.left); queue.offerLast(node.right == null ? emptyNode : node.right); } str.deleteCharAt(str.length() - 1 ); return str.toString(); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 class Solution { TreeNode xParNode = null ; TreeNode yParNode = null ; int xDepth, yDepth; boolean xFound = false , yFound = false ; int x, y; public boolean isCousins (TreeNode root, int x, int y) { this .x = x; this .y = y; dfs(root,0 , null ); return (xDepth == yDepth) && (xParNode != yParNode); } public void dfs (TreeNode node, int depth, TreeNode parNode) { if (node == null ) { return ; } if (node.val == this .x) { xParNode = parNode; xFound = true ; xDepth = depth + 1 ; } if (node.val == this .y) { yParNode = parNode; yFound = true ; yDepth = depth + 1 ; } if (xFound && yFound) { return ; } dfs(node.left, depth + 1 , node); if (xFound && yFound) { return ; } dfs(node.right, depth + 1 , node); } }
回溯 可能要注意的一些问题 1、Deque<int[]>中存放两次temp的,深浅拷贝问题
2、java中集合存储的元素,是对象的引用。
3、int[]这个数组也是对象的,所以说前面的Comparator的时候对int[]
是不能排序的,对int[][]
可以排序的,因为Comparator的时候里面的每一个元素是iny[]
,那么也就是对象了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Deque<List<Integer>> deque = new ArrayDeque <>(); List<Integer> list = new ArrayList <>(); list.add(2 ); deque.add(list); list.set(0 , 123 ); System.out.println(deque.peekFirst().get(0 )); Deque<List<Integer>> deque = new ArrayDeque <>(); List<Integer> list = new ArrayList <>(); list.add(2 ); deque.add(new ArrayList <>(list)); list.set(0 , 123 ); System.out.println(deque.peekFirst().get(0 ));
自己想法 1 、
注意,感觉有些有些题目,跟使用回溯,寻找所有的个数。
不过,动态规划,是找个数,规模会大;而回溯的话是找出所有的种类,所以规模会小,因为时间复杂度高。
2 、
感觉回溯在很多时候,也可以使用那个 二叉树的层序遍历 的做法。(好像就是广度搜索,另一个是深度 + 回溯)
比如笔试过程中的,五个队伍两两比赛,每一次都能得到五个队伍的结果,五个队伍的结果从小到大排序之后,结果不重复的个数。
那我笔试过程中的做法是,通过在每一队比较完成的放入队列中,然后下一次两外两个比的时候,将队列里面的全部取出来,取出来的每一个都加上这次两两比较的情况,然后放入队列中,然后后面的再比,重复的使用set去重。
注意回溯的时候,将一个个ArrayList放入的时候,记得new ArrayList,因为浅拷贝,如果是int[]的话,记得.clone()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public List<List<Integer>> subsetsWithDup (int [] nums) { Arrays.sort(nums); List<Integer> list = new ArrayList <>(); Set<List<Integer>> ans = new HashSet <>(); dfs(list, ans, 0 , nums); return new ArrayList <>(ans); } public void dfs (List<Integer> list, Set<List<Integer>> ans, int cur, int [] nums) { if (nums.length == cur) { ans.add(new ArrayList <>(list)); return ; } list.add(nums[cur]); dfs(list, ans, cur+1 , nums); list.remove(list.size()-1 ); dfs(list, ans, cur+1 , nums); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { Set<List<Integer>> set = new HashSet <>(); public List<List<Integer>> combinationSum (int [] candidates, int target) { List<Integer> list = new ArrayList <Integer>(); dfsTrace(list, 0 , target, candidates, 0 ); return new ArrayList <>(set); } public void dfsTrace (List<Integer> list, int sum, int target, int [] candidates, int curIndex) { if (sum == target) { List<Integer> temp = new ArrayList <>(list); Collections.sort(temp); set.add(temp); return ; } if (sum > target || curIndex >= candidates.length || set.size() >= 150 ) { return ; } dfsTrace(list, sum, target, candidates, curIndex + 1 ); list.add(candidates[curIndex]); dfsTrace(list, sum + candidates[curIndex], target, candidates, curIndex); list.remove(list.size() - 1 ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 class Solution { public boolean canPartitionKSubsets (int [] nums, int k) { nums = Arrays.stream(nums).boxed().sorted((a, b) -> b-a).mapToInt(Integer::valueOf).toArray(); int sum = Arrays.stream(nums).sum(); if (sum % k != 0 ) { return false ; } dfsTrace(0 , nums, 0 , sum / k, 0 , k, new boolean [nums.length]); return ans; } boolean ans = false ; public void dfsTrace (int idx, int [] nums, int curSum, int splitSum, int cnt, int k, boolean [] visited) { if (cnt == k) { ans = true ; return ; } if (curSum == splitSum) { dfsTrace(0 , nums, 0 , splitSum, cnt + 1 , k, visited); } if (curSum >= splitSum || idx >= nums.length) { return ; } for (int i = idx; i < nums.length; i++) { if (!visited[i]) { visited[i] = true ; dfsTrace(i+1 , nums, curSum + nums[i], splitSum, cnt, k, visited); visited[i] = false ; } } } } class Solution { public boolean canPartitionKSubsets (int [] nums, int k) { int n = nums.length; int sum = Arrays.stream(nums).sum(); if (sum % k != 0 ) { return false ; } int per = sum / k; Arrays.sort(nums); if (nums[n-1 ] > per) { return false ; } boolean [] dp = new boolean [1 << n]; int [] curSum = new int [1 << n]; dp[0 ] = true ; for (int i = 0 ; i < 1 << n; i++) { if (!dp[i]) { continue ; } for (int j = 0 ; j < n; j++) { if (curSum[i] + nums[j] > per) { break ; } if ((i & (1 << j)) == 0 ) { int next = i | (1 << j); if (!dp[next]) { curSum[next] = (curSum[i] + nums[j]) % per; dp[next] = true ; } } } } return dp[(1 << n) - 1 ]; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public List<List<Integer>> permute (int [] nums) { dfsTrace(new ArrayList (), nums.length, new boolean [22 ], nums); return ans; } List<List<Integer>> ans = new ArrayList <>(); public void dfsTrace (List<Integer> path, int n, boolean [] visited, int [] nums) { if (path.size() == n) { ans.add(new ArrayList (path)); return ; } for (int i = 0 ; i < nums.length; i++) { if (!visited[nums[i] + 10 ]) { path.add(nums[i]); visited[nums[i] + 10 ] = true ; dfsTrace(path, n, visited, nums); visited[nums[i] + 10 ] = false ; path.remove(path.size() - 1 ); } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 class Solution { public List<List<Integer>> permuteUnique (int [] nums) { Arrays.sort(nums); dfsTrace(nums, nums.length, new ArrayList (), new boolean [22 ]); return new ArrayList <>(ans); } Set<List<Integer>> ans = new HashSet <>(); public void dfsTrace (int [] nums, int n, List<Integer> path, boolean [] visited) { if (path.size() == n) { ans.add(new ArrayList (path)); return ; } for (int i = 0 ; i < nums.length; i++) { if (!visited[i]) { visited[i] = true ; path.add(nums[i]); dfsTrace(nums, n, path, visited); visited[i] = false ; path.remove(path.size() - 1 ); } } } } class Solution { public List<List<Integer>> permuteUnique (int [] nums) { Arrays.sort(nums); dfsTrace(nums, nums.length, new ArrayList (), new boolean [22 ]); return ans; } List<List<Integer>> ans = new ArrayList <>(); public void dfsTrace (int [] nums, int n, List<Integer> path, boolean [] visited) { if (path.size() == n) { ans.add(new ArrayList (path)); return ; } for (int i = 0 ; i < nums.length; i++) { if (i >= 1 && nums[i] == nums[i-1 ] && !visited[i-1 ]) { continue ; } if (!visited[i]) { visited[i] = true ; path.add(nums[i]); dfsTrace(nums, n, path, visited); visited[i] = false ; path.remove(path.size() - 1 ); } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Solution { List<Integer> ori; boolean flag = false ; List<Integer> ans; public List<Integer> nextPermutation (int [] nums) { ori = Arrays.stream(nums).boxed().collect(Collectors.toList()); Arrays.sort(nums); dfs(nums, new ArrayList <>(), 0 , nums.length, new boolean [ori.size()]); for (int i = 0 ; i < nums.length; i++) { System.out.print(ans.get(i) + " " ); } return ans; } void dfs (int [] nums, List<Integer> cur, int curNum, int n, boolean [] visited) { if (cur.size() == n) { if (flag && ans == null ){ ans = new ArrayList <>(cur); } if (cur.equals(ori)) { flag = true ; } return ; } for (int i = 0 ; i < n; i++) { if (!visited[i]) { visited[curNum] = true ; cur.add(nums[i]); dfs(nums, cur, i, n, visited); cur.remove(cur.size() - 1 ); visited[curNum] = false ; } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 class Solution { public List<List<Integer>> combinationSum2 (int [] candidates, int target) { List<List<Integer>> ans = new ArrayList <>(); List<Integer> path = new ArrayList <>(); Arrays.sort(candidates); dfsTrace(candidates, target, 0 , ans, path, 0 ); return ans; } public void dfsTrace (int [] candidates, int target, int sum, List<List<Integer>> ans, List<Integer> path, int curIndex) { if (sum == target) { ans.add(new ArrayList <>(path)); return ; } if (sum >= target || curIndex >= candidates.length) { return ; } int same = 1 ; for (int i=curIndex+1 ; i<candidates.length; i++) { if (candidates[i] == candidates[curIndex]) { same += 1 ; } } dfsTrace(candidates, target, sum, ans, path, curIndex + same); for (int i=0 ; i<same; i++) { path.add(candidates[curIndex]); sum += candidates[curIndex]; dfsTrace(candidates, target, sum, ans, path, curIndex + same); } for (int i=0 ; i<same; i++) { path.remove(path.size()-1 ); sum -= candidates[curIndex]; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public List<List<Integer>> combinationSum (int [] candidates, int target) { List<List<Integer>> ans = new ArrayList <>(); List<Integer> path = new ArrayList <>(); dfsTrace(candidates, target, target, ans, path, 0 ); return ans; } public void dfsTrace (int [] candidates, int target, int res, List<List<Integer>> ans, List<Integer> path, int curIndex) { if (res == 0 ) { ans.add(new ArrayList <>(path)); return ; } if (res < 0 || curIndex >= candidates.length) { return ; } dfsTrace(candidates, target, res, ans, path, curIndex + 1 ); for (int i=1 ; i * candidates[curIndex] <= res; i++) { path.add(candidates[curIndex]); dfsTrace(candidates, target, res - i * candidates[curIndex], ans, path, curIndex + 1 ); } for (int i=1 ; i * candidates[curIndex] <= res; i++) { path.remove(path.size() - 1 ); } } }
①基于选择的回溯(还需要借助set来知道这个数有没有被选择过就行了,好吧不重复没必要用set)
②基于交换的回溯(两两交换来完成,更快)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public List<List<Integer>> permute (int [] nums) { int n = nums.length; List<List<Integer>> ans = new ArrayList <>(); List<Integer> path = new ArrayList <>(); for (int num: nums) { path.add(num); } dfsTrace(nums, path, ans, 0 , n); return ans; } public void dfsTrace (int [] nums, List<Integer> path, List<List<Integer>> ans, int curIndex, int n) { if (curIndex == n) { ans.add(new ArrayList <>(path)); return ; } dfsTrace(nums, path, ans, curIndex + 1 , n); for (int i=curIndex+1 ; i<n; i++) { Collections.swap(path, curIndex, i); dfsTrace(nums, path, ans, curIndex + 1 , n); Collections.swap(path, curIndex, i); } } }
当然用set去重复也可以,但是这样的话,还是比较浪费时间的。
此处选择基于选择的排序。
要解决重复问题,我们只要设定一个规则,保证在填第 idx 个数的时候重复数字只会被填入一次即可。而在本题解中,我们选择对原数组排序,保证相同的数字都相邻,然后每次填入的数一定是这个数所在重复数集合中「从左往右第一个未被填过的数字」。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { boolean [] vis; public List<List<Integer>> permuteUnique (int [] nums) { Arrays.sort(nums); int n = nums.length; List<List<Integer>> ans = new ArrayList <>(); List<Integer> path = new ArrayList <>(); vis = new boolean [n]; Arrays.sort(nums); dfsTrace(nums, path, ans, 0 , n); return ans; } public void dfsTrace (int [] nums, List<Integer> path, List<List<Integer>> ans, int curIndex, int n) { if (curIndex == n) { ans.add(new ArrayList <>(path)); return ; } for (int i=0 ; i<n; i++) { if (vis[i] || i > 0 && !vis[i-1 ] && nums[i-1 ] == nums[i]) { continue ; } path.add(nums[i]); vis[i] = true ; dfsTrace(nums, path, ans, curIndex + 1 , n); path.remove(path.size() - 1 ); vis[i] = false ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { List<List<Integer>> ans = new ArrayList <>(); int n; public List<List<Integer>> subsets (int [] nums) { n = nums.length; Arrays.sort(nums); dfs(nums, 0 , new ArrayList <>()); return ans; } public void dfs (int [] nums, int curIndex, List<Integer> path) { if (curIndex >= n) { ans.add(new ArrayList <>(path)); return ; } dfs(nums, curIndex + 1 , path); path.add(nums[curIndex]); dfs(nums, curIndex + 1 , path); path.remove(path.size() - 1 ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution { List<List<Integer>> ans = new ArrayList <>(); int n; public List<List<Integer>> subsetsWithDup (int [] nums) { n = nums.length; Arrays.sort(nums); dfs(nums, 0 , new ArrayList <>(), new boolean [n]); return ans; } public void dfs (int [] nums, int curIndex, List<Integer> path, boolean [] visited) { if (curIndex >= n) { ans.add(new ArrayList <>(path)); return ; } int count = 1 ; while (curIndex + count < n && nums[count + curIndex] == nums[curIndex]) { count += 1 ; } dfs(nums, curIndex + count, path, visited); for (int i = 0 ; i < count; i++) { path.add(nums[curIndex+i]); visited[curIndex+i] = true ; dfs(nums, curIndex + count, path, visited); } for (int i = 0 ; i < count; i++) { visited[curIndex+i] = false ; path.remove(path.size() - 1 ); } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { public List<List<Integer>> allPathsSourceTarget (int [][] graph) { List<List<Integer>> ans = new ArrayList <>(); List<Integer> path = new ArrayList <Integer>(); path.add(0 ); dfsTrace(ans, graph.length - 1 , graph, path, 0 ); return ans; } public void dfsTrace (List<List<Integer>> ans, int target, int [][] graph, List<Integer> path, int cur) { if (cur == target) { ans.add(new ArrayList <>(path)); return ; } for (int des: graph[cur]) { path.add(des); dfsTrace(ans, target, graph, path, des); path.remove(path.size() - 1 ); } } }
回溯 + 动态规划预处理 【宫水三叶】为什么只需要对第一个字符进行「爆搜」
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 class Solution { public List<List<String>> partition (String s) { int n = s.length(); boolean [][] dp = new boolean [n][n]; char [] chars = s.toCharArray(); List<List<String>> anss = new ArrayList <>(); List<String> ans = new ArrayList <>(); for (int step = 1 ; step <= n; step++) { for (int i=0 ; i<n-step+1 ; i++) { if (step == 1 ) { dp[i][i] = true ; } else if (step == 2 ) { dp[i][i+1 ] = chars[i] == chars[i+1 ]; } else { dp[i][i+step-1 ] = chars[i] == chars[i+step-1 ] && dp[i+1 ][i+step-2 ]; } } } dfsTrace(anss, ans, n, s, 0 , dp); return anss; } public void dfsTrace (List<List<String>> anss, List<String> ans, int n, String s, int cur, boolean [][] dp) { if (cur == n) { anss.add(new ArrayList <>(ans)); return ; } for (int i=cur; i<n; i++) { if (dp[cur][i]) { ans.add(s.substring(cur, i+1 )); dfsTrace(anss, ans, n, s, i+1 , dp); ans.remove(ans.size() - 1 ); } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 class Solution { public int kSimilarity (String s1, String s2) { int n = s1.length(), n2 = s2.length(); if (n != n2) { return -1 ; } StringBuilder sb1 = new StringBuilder (); StringBuilder sb2 = new StringBuilder (); for (int i = 0 ; i < n; i++) { if (s1.charAt(i) != s2.charAt(i)) { sb1.append(s1.charAt(i)); sb2.append(s2.charAt(i)); } } dfsTrace(0 , sb1.toString(), sb2.toString(), 0 , n); return ans; } int ans = Integer.MAX_VALUE; public void dfsTrace (int curIndex, String sb1, String sb2, int k, int n) { if (sb1.equals(sb2)) { ans = Math.min(ans, k); return ; } if (curIndex >= n) { return ; } if (k + xiaXian(curIndex, sb1, sb2) >= ans) { return ; } if (sb1.charAt(curIndex) == sb2.charAt(curIndex)) { dfsTrace(curIndex + 1 , sb1, sb2, k, n); return ; } for (int i = curIndex + 1 ; i < sb1.length(); i++) { if (sb1.charAt(curIndex) == sb2.charAt(i)) { sb2 = swap(sb2, curIndex, i); dfsTrace(curIndex + 1 , sb1, sb2, k + 1 , n); sb2 = swap(sb2, curIndex, i); } } } public String swap (String str, int i, int j) { char [] chars = str.toCharArray(); char temp = chars[i]; chars[i] = chars[j]; chars[j] = temp; return new String (chars); } public int xiaXian (int curINdex, String sb1, String sb2) { int ans = 0 ; for (int i = 0 ; i < sb1.length(); i++) { if (sb1.charAt(i) != sb2.charAt(i)) { ans += 1 ; } } return ans / 2 ; } }
约瑟夫环 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 import java.util.*;public class YueSeFuMoni { public static void main (String[] args) { Deque<Integer> queue = new ArrayDeque <>(); Scanner scanner = new Scanner (System.in); int n = scanner.nextInt(); int k = scanner.nextInt(); for (int i = 0 ; i < n; i++) { queue.offerLast(scanner.nextInt()); } for (int i = 0 ; i < n-1 ; i++) { for (int j = 0 ; j < k-1 ; j++) { queue.offerLast(queue.pollFirst()); } queue.pollFirst(); } System.out.println("模拟:" + queue.pollFirst()); System.out.println("递推(但是数据编号有序):" + findTheWinner(9 , 7 )); } public static int findTheWinner (int n, int k) { int p = 0 ; for (int i = 2 ; i <= n; i++) { p = (p + k) % i; } return p + 1 ; } }
模拟,类似于约瑟夫环,逆着来 题目描述
Alice和Bob在玩一个游戏。有n张卡牌,点数分别为1到n。进行洗牌后,n张牌从上到下叠放形成一个牌堆。每次Alice先将当前牌堆顶的一张牌放到牌堆底,然后Bob再将当前牌堆顶的一张牌放到牌堆底。(特别地,当牌堆中只有一张牌时,相当于不进行任何操作)接着,他们会翻开当前牌堆顶的牌,并记下它的点数。当所有牌都被翻开后,他们也记下了n个点数。现在他们想根据记下的这个序列来还原一开始的牌(从牌堆顶到牌堆底每一张牌的点数)。
输入描述 第一行是一个正整数n,表示有n张牌。接下来一行n个用空格隔开的正整数,第i个数a_i表示第i张被翻开的牌的点数。1<=n<=100000 输出描述 一行n个用空格隔开的正整数,第i个数表示初始牌堆中从牌堆顶到牌堆底的第i张牌的点数。样例输入
4 1 2 3 4 样例输出 4 2 1 3
初始牌堆为:4 2 1 3
Alice和Bob分别操作后牌堆为:1 3 4 2,此时1被翻开,牌堆变为3 4 2
Alice和Bob分别操作后牌堆为:2 3 4,此时2被翻开,牌堆变为3 4
Alice和Bob分别操作后牌堆为:3 4,此时3被翻开,牌堆变为4
Alice和Bob分别操作后牌堆依旧为4,此时4被翻开。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class PuKe { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = Integer.parseInt(scanner.nextLine()); Deque<Integer> queue = new ArrayDeque <>(); int [] nums = Arrays.stream(scanner.nextLine().split(" " )).mapToInt(Integer::valueOf).toArray(); int [] ori = new int [n]; for (int i = 0 ; i < n; i++) { queue.offerLast(i); } for (int i = 0 ; i < n; i++) { queue.offerLast(queue.pollFirst()); queue.offerLast(queue.pollFirst()); ori[queue.pollFirst()] = nums[i]; } for (int i = 0 ; i < n; i++) { System.out.printf("%d " , ori[i]); } } }