刷题总结
1,count数组
#include <iostream> #include <unordered_map> using namespace std; // 输入: 11223344455 // 输出:{1:2, 2: 2, 3: 2, 4: 3, 5: 1} void printNums(vector<int> nums) { for(int i = 0; i < nums.size(); i++) { cout << nums[i] << '\t'; } } vector<pair<int,int>> analysis(vector<int> nums) { unordered_map<int, int> mp; for(int i = 0; i < nums.size(); i++) { if(mp.find(nums[i]) == mp.end()) { mp.insert(pair(nums[i], 1)); } else { mp[nums[i]] = mp.find(nums[i])->second + 1; } } vector<pair<int, int>> result(mp.begin(), mp.end()); sort(result.begin(), result.end(), [](pair<int,int>&a, pair<int, int>&b) { return a.second < b.second; }); return result; } void printPair(vector<pair<int, int>> &nums) { for(int i = 0; i < nums.size(); i++) { cout << nums[i].first << ": " << nums[i].second << "\t"; } } int main() { vector<int> nums = {7, 7, 2, 2, 3, 3, 4, 4 , 4, 5, 5}; // printNums(nums); vector<pair<int, int>> result = analysis(nums); printPair(result); }
2, leetcode 1. 两数之和
class Solution { public int[] twoSum(int[] nums, int target) { Map<Integer, Integer> mp = new HashMap<>(); for(int i = 0; i < nums.length; i++) { if(mp.containsKey(target - nums[i])) { return new int[] {i, mp.get(target-nums[i])}; } mp.put(nums[i], i); } return new int[2]; } }
3,leetcode 4.寻找两个有序数组的中位数
解法一:
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { // 合并两个数组 ArrayList<Integer> array = new ArrayList<>(); int i = 0, j = 0; while(i < nums1.length || j < nums2.length) { if(i < nums1.length && j < nums2.length && nums1[i] < nums2[j]) { array.add(nums1[i++]); } else if(j < nums2.length && i < nums1.length && nums1[i] >= nums2[j]) { array.add(nums2[j++]); }else if (j < nums2.length) { array.add(nums2[j++]); } else if (i < nums1.length) { array.add(nums1[i++]); } } int totalLength = nums1.length + nums2.length; int middle = (totalLength - 1) / 2; if(totalLength % 2 == 0) { return (array.get(middle) + array.get(middle+1) )/ 2.0; } else { return array.get(middle); } } }
解法二:
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { int m = nums1.length; int n = nums2.length; if(m > n) { return findMedianSortedArrays(nums2, nums1); } int c1 = 0, c2 = 0, lo = 0, hi = 2*m, LMAX1 = 0, LMAX2 = 0, RMIN1 = 0, RMIN2 = 0; while(lo <= hi) { c1 = (lo + hi) / 2; c2 = m + n - c1; LMAX1 = (c1 == 0) ? Integer.MIN_VALUE : nums1[(c1-1)/2]; LMAX2 = (c2 == 0) ? Integer.MIN_VALUE : nums2[(c2-1)/2]; RMIN1 = (c1 == 2*m) ? Integer.MAX_VALUE : nums1[c1/2]; RMIN2 = (c2 == 2*n) ? Integer.MAX_VALUE : nums2[c2/2]; if(LMAX1 > RMIN2) { hi = c1 - 1; } else if(LMAX2 > RMIN1) { lo = c1 + 1; } else { break; } } return (Math.max(LMAX1, LMAX2) + Math.min(RMIN1, RMIN2)) / 2.0; } }
4,leetcode 11.盛水最多的容器
解法一(暴力)
class Solution { public int maxArea(int[] height) { int max = Integer.MIN_VALUE; int len = height.length; int tmp = 0; for(int i = 0; i < len - 1; i++) { for (int j = i + 1; j < len; j++) { tmp = (j - i)*(Math.min(height[i], height[j])); if(tmp > max) { max = tmp; } } } return max; } }
解法二(双指针)
class Solution { public int maxArea(int[] height) { int res = Integer.MIN_VALUE; int i = 0, j = height.length - 1; while(i < j) { if(height[i] < height[j]){ res = Math.max(res, height[i]*(j - i)); i++; } else { res = Math.max(res, height[j]*(j - i)); j--; } } return res; } }
5, leetcode 15. 三数之和
class Solution { public List<List<Integer>> threeSum(int[] nums) { List<List<Integer>> result = new ArrayList(); int len = nums.length; if(len < 3) return result; Arrays.sort(nums); for(int i = 0; i < len; i++) { if(nums[i] > 0) break; if(i > 0 && nums[i] == nums[i-1]) continue; int L = i+1, R = len - 1; while(L < R) { int sum = nums[i] + nums[L] + nums[R]; if(sum == 0) { result.add(Arrays.asList(nums[i], nums[L], nums[R])); while(L < R && nums[L] == nums[L+1]) L++; while(L < R && nums[R] == nums[R-1]) R--; L++; R--; } if(sum > 0) R--; if(sum < 0) L++; } } return result; } }
6, leetcode 16. 最接近三数之和
class Solution { public int threeSumClosest(int[] nums, int target) { int len = nums.length; if(len < 3) return 0; int result = nums[0] + nums[1] + nums[2]; Arrays.sort(nums); for(int i = 0; i < len; i++) { int L = i + 1; int R = len - 1; while(L < R) { int sum = nums[i] + nums[L] + nums[R]; result = Math.abs(result - target) > Math.abs(sum - target) ? sum : result; if(sum > target) { R--; }else if(sum < target) { L++; }else { return target; } } } return result; } }
7, leetcode 18. 四数之和
class Solution { public List<List<Integer>> fourSum(int[] nums, int target) { List<List<Integer>> result = new ArrayList(); int len = nums.length; if(len < 4) return result; Arrays.sort(nums); for(int i = 0; i <= len - 4; i++) { if(i > 0 && nums[i] == nums[i-1]) continue; for(int j = i+1; j <= len - 3; j++) { if(j > i+1 && nums[j] == nums[j-1]) continue; int l = j+1, r = len - 1; while(l < r) { int sum = nums[i] + nums[j] + nums[l] + nums[r]; if(sum > target) { r--; }else if(sum < target) { l++; }else { result.add(Arrays.asList(nums[i], nums[j], nums[l], nums[r])); while(nums[l]==nums[l+1]) l++; while(nums[r] == nums[r-1]) r--; l++; r--; } } } } return result; } }
8. leetcode 26. 删除排序数组中的重复项
解法一:(暴力移动法)
class Solution { public int removeDuplicates(int[] nums) { //判断重复 记录位置 删除 int end = nums.length, i = 0; while(i < end) { if(i > 0 && nums[i] == nums[i-1]) { //移动 for(int j = i+1; j < end; j++) { nums[j-1] = nums[j]; } end--; }else { i++; } } return end; } }
解法二:(双指针法)
class Solution { public int removeDuplicates(int[] nums) { int len = nums.length; if(len == 0) return 0; else if(len == 1) return 1; else { int i = 0; for(int j = 1; j < len; j++) { if(nums[i] != nums[j]) { i++; nums[i] = nums[j]; } } return i+1; } } }
9. leetcode 3. 无重复字符的最长字串
解法一:
class Solution { public int lengthOfLongestSubstring(String s) { int len = s.length(); int i = 0; int result = 0; while(i < len) { Set<String> set= new HashSet(); int j = 0; for(j = i; j < len; j++) { if(!set.contains(s.charAt(j)+"")) { result = Math.max(result, j-i+1); }else { break; } set.add(s.charAt(j)+""); } i++; } return result; } }
解法二:(滑动窗口)
class Solution { public int lengthOfLongestSubstring(String s) { int LeftIndex = 0; int result = 0; for(int j = 0; j < s.length(); j++) { for(int CurIndex = LeftIndex; CurIndex < j; CurIndex++) { if(s.charAt(CurIndex) == s.charAt(j)) { result = Math.max(result, j - LeftIndex); LeftIndex = CurIndex + 1; break; } } } return Math.max(s.length()-LeftIndex, result); } }
10. leetcode 27. 移除元素
解法一:
class Solution { public int removeElement(int[] nums, int val) { int i = 0; for(int j = 0; j < nums.length; j++) { if(nums[j] != val) { nums[i] = nums[j]; i++; } } return i; } }
解法二:
class Solution { public int removeElement(int[] nums, int val) { int len = nums.length; int i = 0; while(i < len) { if(nums[i] == val) { nums[i] = nums[len-1]; len--; }else { i++; } } return len; } }
11. leetcode 6. Z字形变换
解法一:
class Solution { public String convert(String s, int numRows) { int len = s.length(); //根据s的长度 和numRows来分配初始数组的大小 StringBuilder sb = new StringBuilder(); if(len == 0) return sb.toString(); if(numRows == 1) return s; int numCols = (len / (2*numRows - 2) + 1) * (numRows-1); char[][] result = new char[numRows][numCols]; int i = 0, row = 0, col = 0; while(i < len) { for(int j = 0; j < numRows && i < len; j++) { result[j][col] = s.charAt(i++); } col++; for(int j = numRows-2; j >= 1 && i < len; j--) { result[j][col++] = s.charAt(i++); } } for(i = 0; i < result.length; i++) { for(int j = 0; j < result[0].length; j++) { if(result[i][j] != '\0') { sb.append(result[i][j]); } } } return sb.toString(); } }
解法二:
class Solution { public String convert(String s, int numRows) { int len = s.length(); numRows = Math.min(numRows, len); if(numRows == 1) return s; //构造stringbuilder List<StringBuilder> sb = new ArrayList<>(); for(int i = 0; i < numRows; i++) { sb.add(new StringBuilder()); } boolean goDown = false; int row = 0; for(int i = 0; i < len; i++) { sb.get(row).append(s.charAt(i)); if(row == 0 || row == numRows - 1) goDown = !goDown; row += goDown ? 1 : -1; } StringBuilder res = new StringBuilder(); for(int i = 0; i < sb.size(); i++) { res.append(sb.get(i)); } return res.toString(); } }
12. leetcode 5. 最长回文子串
解法一:(暴力)
class Solution { public String longestPalindrome(String s) { if(s.length() < 2) return s; String res = s.substring(0, 1); int maxLen = 1; for(int i = 0; i < s.length() - 1; i++) { for(int j = i + 1; j < s.length(); j++) { if(j-i+1 > maxLen && valid(i, j, s)) { maxLen = j - i + 1; res = s.substring(i, j+1); } } } return res; } public boolean valid(int i, int j, String s) { char[] ss = s.toCharArray(); while(i <= j) { if(ss[i++] != ss[j--]) { return false; } } return true; } }
解法二:(中心扩散法)
class Solution { public String longestPalindrome(String s) { int len = s.length(); if(len < 2) return s; String res = s.substring(0, 1); int maxLen = 1; for(int i = 0; i < len-1; i++) { String s1 = centerS(s, i, i); String s2 = centerS(s, i, i+1); String maxS = s1.length() > s2.length() ? s1 : s2; if(maxS.length() > maxLen) { maxLen = maxS.length(); res = maxS; } } return res; } public String centerS(String s, int l, int r) { int len = s.length(); while(l >= 0 && r < len) { if(s.charAt(l) == s.charAt(r)) { l--; r++; } else { break; } } return s.substring(l+1, r); } }
解法三:(动态规划)
class Solution { public String longestPalindrome(String s) { int len = s.length(); if(len < 2) return s; boolean[][] dp = new boolean[len][len]; String res = s.substring(0, 1); int maxLen = 1; for(int r = 1; r < len; r++) { for(int l = 0; l < r ; l++) { if(s.charAt(l) == s.charAt(r) && (r - l <= 2 || dp[l+1][r-1])) { dp[l][r] = true; if(r - l + 1 > maxLen) { maxLen = r - l + 1; res = s.substring(l, r+1); } } } } return res; } }
13. leetcode 102. 二叉树的层次遍历
解法一:(递归)
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public static List<List<Integer>> res; public List<List<Integer>> levelOrder(TreeNode root) { res = new ArrayList<>(); if(root == null) return res; helper(root, 0); return res; } public void helper(TreeNode root, int level) { if(res.size() == level) { res.add(new ArrayList()); } res.get(level).add(root.val); if(root.left != null) { helper(root.left, level+1); } if(root.right != null) { helper(root.right, level+1); } } }
解法二:(迭代)
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<List<Integer>> levelOrder(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); if(root == null) return res; Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); while(!queue.isEmpty()) { int _size = queue.size(); List<Integer> tmp = new ArrayList<>(); for(int i = 0; i < _size; i++) { TreeNode node = queue.remove(); tmp.add(node.val); if(node.left != null) { queue.offer(node.left); } if(node.right != null) { queue.offer(node.right); } } res.add(tmp); } return res; } }
14. leetcode 103. 二叉树的锯齿形层次遍历
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<List<Integer>> zigzagLevelOrder(TreeNode root) { List<List<Integer>> res = new ArrayList<>(); if(root == null) return res; Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); while(!queue.isEmpty()) { int _size = queue.size(); List<Integer> tmp = new ArrayList<>(); for(int i = 0; i < _size; i++) { TreeNode node = queue.remove(); tmp.add(node.val); if(node.left != null){ queue.offer(node.left); } if(node.right != null) { queue.offer(node.right); } } if(res.size()%2 == 0) { res.add(tmp); } else { Collections.reverse(tmp); res.add(tmp); } } return res; } }
15, leetcode 100.相同的树
解法一:(递归)
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isSameTree(TreeNode p, TreeNode q) { if(p == null && q == null) return true; else if(p == null || q == null) return false; else { if(p.val != q.val) return false; } return isSameTree(p.left, q.left) && isSameTree(p.right, q.right); } }
16, leetcode 96. 不同的二叉搜索树
class Solution { public int numTrees(int n) { //动态规划 , 转移函数通过找规律 //dp[i] += dp[i-1]*dp[n-i] int[] dp = new int[n+1]; dp[0] = 1; dp[1] = 1; for(int i = 2; i < n+1; i++) { for(int j = 1; j <= i; j++) { dp[i] += dp[j-1]*dp[i-j]; } } return dp[n]; } }
17, leetcode 8. 字符串转整数(atoi)
解法一(发生越界):
class Solution { public int myAtoi(String str) { int len = str.length(); if(len == 0) return 0; int start = findFirst(str); if(start == len) return 0; if(str.charAt(start) == '+') { return cal(str, start+1); } else if (str.charAt(start) == '-') { return 0 - cal(str, start+1); } else { return cal(str, start); } } public int cal(String str, int start) { int res = 0; int len = str.length(); for(int i = start; i < len; i++) { char c = str.charAt(i); if(isNum(c)) { res += (c - '0'); res *= 10; } else { break; } } return res/10; } public int findFirst(String str) { int len = str.length(); int i = 0; while(i < len) { if(str.charAt(i) == '+' || str.charAt(i) == '-' || (str.charAt(i) >= '0' && str.charAt(i) <= '9')) { return i; } else if (str.charAt(i) != ' ') { return len; } i++; } return i; } public boolean isNum(char c) { if(c >= '0' && c <= '9') { return true; } return false; } }
改进:
class Solution { public boolean flag = true; public int myAtoi(String str) { int len = str.length(); if(len == 0) return 0; int start = findFirst(str); if(start == len) return 0; return cal(str, start); } public int cal(String str, int start) { int res = 0; int len = str.length(); for(int i = start; i < len; i++) { char c = str.charAt(i); if(isNum(c)) { res = res*10 + (c - '0'); if( flag && i+1 < len && isNum(str.charAt(i+1)) &&( res > Integer.MAX_VALUE / 10 ||res == Integer.MAX_VALUE/10 && str.charAt(i+1) - '0' > Integer.MAX_VALUE%10)) { return Integer.MAX_VALUE ; } if(!flag && i+1 < len && isNum(str.charAt(i+1)) &&( -res < Integer.MIN_VALUE / 10 ||-res == Integer.MIN_VALUE/10 && -(str.charAt(i+1) - '0') < Integer.MIN_VALUE%10)) { return Integer.MIN_VALUE ; } } else { break; } } return flag ? res : res*(-1); } public int findFirst(String str) { int len = str.length(); int i = 0; while(i < len) { if(str.charAt(i) == '+') { flag = true; return i+1; }else if(str.charAt(i) == '-') { flag = false; return i+1; }else if (str.charAt(i) >= '0' && str.charAt(i) <= '9') { return i; } else if (str.charAt(i) != ' ') { return len; } i++; } return i; } public boolean isNum(char c) { if(c >= '0' && c <= '9') { return true; } return false; } }
解法二:(正则表达式):
class Solution(object): def myAtoi(self, str): """ :type str: str :rtype: int """ return max(min(int(*re.findall(r'^[\+|\-]?\d+', str.lstrip())), 2**31-1), -2**31)
这道题硬磕了一个小时,边界情况还是含糊不清,需要集中注意力。加油!!
18, leetcode 13.罗马数字转整数
class Solution { public int romanToInt(String s) { int len = s.length(); if(len == 0) return 0; int i = 0; int res = 0; while(i < len) { if(i < len && s.charAt(i) == 'M') { res += 1000; i++; } if(i < len && s.charAt(i) == 'D') { res += 500; i++; } if(i < len && s.charAt(i) == 'C' && (i+1 < len &&!(s.charAt(i+1) == 'D' || s.charAt(i+1) == 'M') || i+1 >= len)) { res += 100; i++; } else if (i < len && s.charAt(i) == 'C' && i+1 < len && (s.charAt(i+1) == 'D')) { res += 400; i += 2; } else if(i < len && s.charAt(i) == 'C' && i+1 < len && (s.charAt(i+1) == 'M')) { res += 900; i += 2; } if(i < len && s.charAt(i) == 'L') { res += 50; i++; } if (i < len && s.charAt(i) == 'X' && (i+1 < len &&!(s.charAt(i+1) == 'L' || s.charAt(i+1) == 'C') || i+1 >= len)) { res += 10; i++; } else if (i < len && s.charAt(i) == 'X' && i+1 < len && s.charAt(i+1) == 'L') { res += 40; i += 2; } else if(i < len && s.charAt(i) == 'X' && i+1 < len &&(s.charAt(i+1) == 'C')) { res += 90; i += 2; } if(i < len && s.charAt(i) == 'V') { res += 5; i++; } if(i < len && s.charAt(i) == 'I' &&( i+1 < len &&!(s.charAt(i+1) == 'V' || s.charAt(i+1) == 'X') || i+1 >= len)) { res += 1; i++; } else if(i < len && s.charAt(i) == 'I' && i+1 < len && s.charAt(i+1) == 'V') { res += 4; i += 2; } else if(i < len && s.charAt(i) == 'I' && i+1 < len && s.charAt(i+1) == 'X') { res += 9; i += 2; } } return res; } }
这个解题方法很恐怖,首先边界情况太多,还有很多重复的代码块,不好维护。全程if else,写的也很耽误时间,特别需要优化。
解法二:其实在写以上题解过程中,也是想到要不要将值存到hashmap里面,这样直接读取就好了,无奈懒得更进一步去思考IV这种情况。就是直接去hashmap里面取值嘛,取不到就取单个字符的。
class Solution { public int romanToInt(String s) { Map<String, Integer> map = new HashMap<>(); map.put("I", 1); map.put("V", 5); map.put("X", 10); map.put("L", 50); map.put("C", 100); map.put("D", 500); map.put("M", 1000); map.put("IV", 4); map.put("IX", 9); map.put("XL", 40); map.put("XC", 90); map.put("CD", 400); map.put("CM", 900); int len = s.length(); if(len == 0) return 0; int i = 0; int res = 0; while(i < len) { if(i < len && i+2 <= len && map.containsKey(s.substring(i, i+2))) { res += map.get(s.substring(i, i+2)); i += 2; }else if(i < len && map.containsKey(s.substring(i, i+1))) { res += map.get(s.substring(i, i+1)); i +=1; } } return res; } }
19,leetcode 14. 最长公共前缀
class Solution { public String longestCommonPrefix(String[] strs) { int index = 0; int len = strs.length; if(len < 1 ||(len >= 0 && strs[0].length() == 0)) return ""; StringBuilder sb = new StringBuilder(); boolean flag = true; while(flag && index < strs[0].length()) { char c = strs[0].charAt(index); for(int i = 1; i < len; i++) { if(index < strs[i].length() && strs[i].charAt(index) != c || index >= strs[i].length()) { flag = false; break; } } if (flag) sb.append(strs[0].charAt(index)); index++; } return sb.toString(); } }
20, leetcode 12.整数转罗马数字
class Solution { public String intToRoman(int num) { String[] romans = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; int[] nums = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; if(num <= 0) return ""; StringBuilder sb = new StringBuilder(); while(num > 0) { for(int i = 0; i < 13; i++) { if(num >= nums[i]) { num -= nums[i]; sb.append(romans[i]); break; } } } return sb.toString(); } }
21, leetcode 17. 电话号码的字母组合
class Solution { public List<String> letterCombinations(String digits) { StringBuilder sb = new StringBuilder(); int len = digits.length(); if(len == 0) return result; backtrack("", digits); return result; } public List<String> result = new ArrayList<>(); String[] mm = {"abc", "def", "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz"}; public void backtrack(String combinations, String digits) { if(digits.length() == 0) { result.add(combinations); return; }else { String ss = mm[digits.charAt(0)-'2']; for(int i = 0; i < ss.length(); i++) { backtrack(combinations+ss.substring(i, i+1), digits.substring(1)); } } } }
22, leetcode 401. 二进制手表
class Solution { public List<String> readBinaryWatch(int num) { if(num == 0) { result.add("0:00"); return result; } if(num > 0 && num <= 10) { backtrack(0, num); } return result; } public List<String> result = new ArrayList<>(); public int[] time = {480, 240, 120, 60, 32, 16, 8, 4, 2, 1}; public boolean[] visited = new boolean[10]; public void backtrack(int combinations, int nums) { if(nums == 0) { int h = combinations / 60; int s = combinations % 60; String tmp = ""; if(s < 10) { tmp = String.format("%d:0%d", h, s); } else { tmp = String.format("%d:%d", h, s); } result.add(tmp); return; } else { for(int i = 0; i < 10; i++) { if(!visited[i]) { combinations += time[i]; visited[i] = true; backtrack(combinations, nums-1); combinations -= time[i]; visited[i] = false; } } } } }
以上的解法不对,是因为,小时只能重用一次,分钟只能重用一次,而不是小时和分钟加起来只能重用一次。//不是, 每一次只能使用一个元素。
class Solution { public List<String> readBinaryWatch(int num) { if(num == 0) { result.add("0:00"); return result; } if(num > 0 && num <= 10) { backtrack(0, num, 0); } return result; } public List<String> result = new ArrayList<>(); public int[] time = {480, 240, 120, 60, 32, 16, 8, 4, 2, 1}; public boolean[] visited = new boolean[10]; public void backtrack(int combinations, int nums, int start) { int h = combinations / 60; int s = combinations % 60; if(nums == 0) { String tmp = ""; if(s < 10) { tmp = String.format("%d:0%d", h, s); } else { tmp = String.format("%d:%d", h, s); } result.add(tmp); return; } else { for(int i = start; i < 10; i++) { if(i < 4 ) { combinations += time[i]; if(h + time[i]/60 < 12) backtrack(combinations, nums-1, i+1); combinations -= time[i]; } else { combinations += time[i]; if(s + time[i] < 60) backtrack(combinations, nums-1, i+1); combinations -= time[i]; } } } } }
23, leetcode 784. 字母大小写全排列
class Solution { public List<String> letterCasePermutation(String S) { backtrack("", 0, S); return result; } public List<String> result = new ArrayList<>(); public void backtrack(String combinations, int start, String nextString) { if(nextString.length() == start) { result.add(combinations); return; } else { for(int i = start; i < nextString.length(); i++) { String tmp = nextString.substring(i, i+1); String tt = transfer(tmp); backtrack(combinations+tt, start+1, nextString); } } } public String transfer(String tt) { String tmp = tt; if(tt.length() != 0) { char c = tt.charAt(0); if(Character.isUpperCase(c)) { tmp = tt.toLowerCase(); } else if (Character.isLowerCase(c)) { tmp = tt.toUpperCase(); } } return tmp; } }
不知道以上的思路是什么玩意,到现在都没想明白
得出了一下的输出
输入:"a1b2"
输出:["A1B2","A122","ABB2","AB22","A2B2","A222","11B2","1122","1BB2","1B22","12B2","1222","B1B2","B122","BBB2","BB22","B2B2","B222","21B2","2122","2BB2","2B22","22B2","2222"]
预期结果:
["a1b2","a1B2","A1b2","A1B2"]
class Solution { public List<String> letterCasePermutation(String S) { Stack<Character> stack = new Stack<>(); dfs(S, 0, stack); return res; } public List<String> res = new ArrayList<>(); public void dfs(String S, int index, Stack<Character> stack) { if(S.length() == index) { StringBuilder sb = new StringBuilder(); for(int i = 0; i < index; i++) { sb.append(stack.get(i)); } res.add(sb.toString()); return; } stack.add(S.charAt(index)); dfs(S, index+1, stack); stack.pop(); if(Character.isUpperCase(S.charAt(index))) { stack.add(S.substring(index, index+1).toLowerCase().charAt(0)); dfs(S, index+1, stack); stack.pop(); } else if(Character.isLowerCase(S.charAt(index))) { stack.add(S.substring(index, index+1).toUpperCase().charAt(0)); dfs(S, index+1, stack); stack.pop(); } } }
递回溯算法框架:
非递归:
1: int a[n],i; 2: 初始化数组a[]; 3: i = 1; 4: while (i>0(有路可走) and (未达到目标)) // 还未回溯到头 5: { 6: if(i > n) // 搜索到叶结点 7: { 8: 搜索到一个解,输出; 9: } 10: else // 处理第i个元素 11: { 12: a[i]第一个可能的值; 13: while(a[i]在不满足约束条件且在搜索空间内) 14: { 15: a[i]下一个可能的值; 16: } 17: if(a[i]在搜索空间内) 18: { 19: 标识占用的资源; 20: i = i+1; // 扩展下一个结点 21: } 22: else 23: { 24: 清理所占的状态空间; // 回溯 25: i = i –1; 26: } 27: }
递归:
1: int a[n]; 2: try(int i) 3: { 4: if(i>n) 5: 输出结果; 6: else 7: { 8: for(j = 下界; j <= 上界; j=j+1) // 枚举i所有可能的路径 9: { 10: if(fun(j)) // 满足限界函数和约束条件 11: { 12: a[i] = j; 13: ... // 其他操作 14: try(i+1); 15: 回溯前的清理工作(如a[i]置空值等); 16: } 17: } 18: } 19: }
24. leetcode 78. 子集
class Solution { public List<List<Integer>> subsets(int[] nums) { Stack<Integer> stack = new Stack(); backtrack(nums, 0, stack); return res; } public List<List<Integer>> res = new ArrayList(); public void backtrack(int[] nums, int start, Stack<Integer> stack) { List<Integer> list = new ArrayList(); for(int j = 0; j < stack.size(); j++) { list.add(stack.get(j)); } res.add(list); if(start == nums.length) { return; } else { for(int i = start; i < nums.length; i++) { stack.add(nums[i]); backtrack(nums, i+1, stack); stack.pop(); } } } }
25, leetcode 51. N皇后
class Solution { public List<List<String>> solveNQueens(int n) { Stack<Integer> stack = new Stack(); boolean[] cols = new boolean[n]; boolean[] master = new boolean[2*n]; boolean[] slave = new boolean[2*n]; if(n == 0) return res; backtrack(n, 0, stack, cols, master, slave); return res; } public List<List<String>> res = new ArrayList(); public void backtrack(int n, int row, Stack<Integer> stack, boolean[] cols, boolean[] master, boolean[] slave) { if(row == n) { List<String> tmp = convert(stack, n); res.add(tmp); return; } else { for(int i = 0; i < n; i++) { if(!cols[i] && !master[row+i] && !slave[row-i+n-1]) { stack.add(i); cols[i] = true; master[row+i] = true; slave[row-i+n-1] = true; backtrack(n, row+1, stack, cols, master, slave); stack.pop(); cols[i] = false; master[row+i] = false; slave[row-i+n-1] = false; } } } } public List<String> convert(Stack<Integer> stack, int n) { List<String> result = new ArrayList(); for(int i = 0; i < n; i++) { int k = stack.get(i); StringBuilder sb = new StringBuilder(); for(int j = 0; j < n; j++) { if(j == k) { sb.append('Q'); } else { sb.append('.'); } } result.add(sb.toString()); } return result; } }
26. leetcode 22.括号生成
class Solution { public List<String> generateParenthesis(int n) { if(n == 0) return result; Stack<Character> stack = new Stack(); backtrack(n, 0, 0, stack); return result; } public List<String> result = new ArrayList(); public void backtrack(int n, int left, int right, Stack<Character> stack) { if(left == right && right == n) { StringBuilder sb = new StringBuilder(); for(int i = 0; i < stack.size(); i++) { sb.append(stack.get(i)); } result.add(sb.toString()); } else { if(left == right && left < n) { stack.add('('); backtrack(n, left+1, right, stack); stack.pop(); } else if (left > right && left < n) { stack.add('('); backtrack(n, left+1, right, stack); stack.pop(); stack.add(')'); backtrack(n, left, right+1, stack); stack.pop(); } else if(left > right && left == n) { stack.add(')'); backtrack(n, left, right+1, stack); stack.pop(); } } } }
解法二(动态规划)
class Solution { public List<String> generateParenthesis(int n) { List<String> result = new ArrayList(); List<List<String>> dp = new ArrayList(); dp.add(Arrays.asList("")); dp.add(Arrays.asList("()")); for(int i = 2; i <= n; i++) { List<String> tmp = new ArrayList(); for(int j = 0; j < i; j++) { List<String> p = dp.get(j); List<String> q = dp.get(i - 1 - j); for(String t1 : p) { for(String t2 : q) { String tt = "(" + t1 + ")" + t2; tmp.add(tt); } } } dp.add(tmp); } return dp.get(n); } }
27, leetcode 39. 组合总和
class Solution { public List<List<Integer>> combinationSum(int[] candidates, int target) { backtrack(candidates, target, new Stack<Integer>(), 0, 0); return result; } public List<List<Integer>> result = new ArrayList(); public void backtrack(int[] candidates, int target, Stack<Integer> stack, int sum, int start) { if(sum == target) { List<Integer> tmp = new ArrayList(); for(int i = 0; i < stack.size(); i++) { tmp.add(stack.get(i)); } result.add(tmp); } else { if(sum < target) { for(int i = start; i < candidates.length; i++) { if(sum + candidates[i] <= target) { stack.add(candidates[i]); backtrack(candidates, target, stack, sum+candidates[i], i); stack.pop(); } } } } } }
28, leetcode 95. 不同的二叉搜索树II
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<TreeNode> generateTrees(int n) { if(n == 0) return res; return backtrack(1, n); } List<TreeNode> res = new ArrayList(); public List<TreeNode> backtrack(int start, int end) { List<TreeNode> result = new ArrayList(); if(start > end) { result.add(null); return result; } if(start == end) { TreeNode node = new TreeNode(start); result.add(node); return result; } for(int i = start; i <= end; i++) { List<TreeNode> leftNode = backtrack(start, i-1); List<TreeNode> rightNode = backtrack(i+1, end); for(TreeNode left : leftNode) { for(TreeNode right : rightNode) { TreeNode node = new TreeNode(i); node.left = left; node.right = right; result.add(node); } } } return result; } }
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<TreeNode> generateTrees(int n) { List<List<TreeNode>> dp = new ArrayList(); List<TreeNode> tt = new ArrayList(); tt.add(null); dp.add(tt); if(n == 0) return new ArrayList(); for(int i = 1; i <= n; i++) { List<TreeNode> tmp = new ArrayList(); for(int j = 1; j <= i; j++) { List<TreeNode> left = dp.get(j-1); List<TreeNode> right = dp.get(i-j); for(TreeNode l : left) { for(TreeNode r : right) { TreeNode node = new TreeNode(j); node.left = l; node.right = clone(r, j); tmp.add(node); } } } dp.add(tmp); } return dp.get(n); } public TreeNode clone(TreeNode node, int offset) { if(node == null) { return null; } TreeNode n = new TreeNode(node.val+offset); n.left = clone(node.left, offset); n.right = clone(node.right, offset); return n; } }
29, leetcode 98.验证二叉搜索树
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isValidBST(TreeNode root) { return isBST(root, Long.MIN_VALUE, Long.MAX_VALUE); } public boolean isBST(TreeNode root, long minVal, long maxVal) { if(root == null) { return true; } if(root.val <= minVal || root.val >= maxVal) { return false; } return isBST(root.left, minVal, root.val)&&isBST(root.right, root.val, maxVal); } }
这里需要注意最大值最小值的类型,需要用Long 或者Double来表示,Integer不行。比如[Integer.MAX_VALUE]这个例子就会报错。 这个解法不通用,虽然简单。下面写一个更常用的解法,采用中序遍历来判断BST
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public boolean isValidBST(TreeNode root) { return isBST(root); } public TreeNode pre = null; public boolean isBST(TreeNode root) { if(root == null) return true; if(!isBST(root.left)) { return false; } if(pre != null && pre.val >= root.val) { return false; } pre = root; return isBST(root.right); } }
30, leetcode 104.二叉树的最大深度
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int maxDepth(TreeNode root) { if(root == null) return depth; queue.add(root); while(!queue.isEmpty()) { int len = queue.size(); for(int i = 0; i < len ; i++) { TreeNode tmp = queue.remove(); if(tmp.left != null) queue.offer(tmp.left); if(tmp.right != null) queue.offer(tmp.right); } depth++; } return depth; } public int depth = 0; public Queue<TreeNode> queue = new LinkedList(); }
方法二(递归):
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public int maxDepth(TreeNode root) { if(root == null) return 0; int maxL = maxDepth(root.left); int maxR = maxDepth(root.right); return Math.max(maxL, maxR)+1; } }
31 leetcode 99. 恢复二叉树
难点:
很难想到恢复的细节,主要是找到规律
记录两个节点,第一个节点是第一次前面节点大于后面节点,取前节点
第二个节点是第二次出现的前面节点大于后面节点,取后面节点。
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public void recoverTree(TreeNode root) { inOrder(root); int tmp = first.val; first.val = second.val; second.val = tmp; } public TreeNode first = null; public TreeNode pre = new TreeNode(Integer.MIN_VALUE); public TreeNode second = null; public void inOrder(TreeNode root) { if(root == null) return; inOrder(root.left); if (first == null && pre != null && pre.val > root.val){ first = pre; } if(first != null && pre != null && pre.val > root.val) { // int tmp = root.val; // root.val = first.val; // first.val = tmp; // return; second = root; } pre = root; inOrder(root.right); } }
32. leetcode 105. 从前序与中序遍历序列构造二叉树
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode buildTree(int[] preorder, int[] inorder) { Map<Integer, Integer> map = new HashMap<>(); for(int i = 0; i < inorder.length; i++) { map.put(inorder[i], i); } return buildTreeHelper(preorder, 0, preorder.length, inorder, 0, inorder.length, map); } public TreeNode buildTreeHelper(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end, Map<Integer, Integer>map){ if(p_start == p_end) { return null; } int root_val = preorder[p_start]; TreeNode root = new TreeNode(root_val); int i_root = map.get(root_val); int len = i_root - i_start; root.left = buildTreeHelper(preorder, p_start+1, p_start+len+1, inorder, i_start, i_root, map); root.right = buildTreeHelper(preorder, p_start+len+1, p_end, inorder, i_root+1, i_end, map); return root; } }
33. leetcode 106. 从中序与后序遍历序列构造二叉树
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public TreeNode buildTree(int[] inorder, int[] postorder) { Map<Integer, Integer> map = new HashMap<>(); for(int i = 0; i < inorder.length; i++) { map.put(inorder[i], i); } return buildTreeHelper(inorder, 0, inorder.length, postorder, 0, postorder.length, map); } public TreeNode buildTreeHelper(int[] inorder, int i_start, int i_end, int[] postorder, int p_start, int p_end, Map<Integer, Integer> map) { if(i_start == i_end) { return null; } int root_val = postorder[p_end-1]; TreeNode root = new TreeNode(root_val); int index = map.get(root_val); int len = index - i_start; root.left = buildTreeHelper(inorder, i_start, index, postorder, p_start, p_start+len, map); root.right = buildTreeHelper(inorder, index+1, i_end, postorder, p_start+len, p_end-1, map); return root; } }
34. leetcode 107. 二叉树的层次遍历II
/** * Definition for a binary tree node. * public class TreeNode { * int val; * TreeNode left; * TreeNode right; * TreeNode(int x) { val = x; } * } */ class Solution { public List<List<Integer>> levelOrderBottom(TreeNode root) { List<List<Integer>> result = new ArrayList<>(); if(root == null) return result; Queue<TreeNode> queue = new LinkedList<>(); queue.offer(root); while(!queue.isEmpty()) { List<Integer> tmp = new ArrayList<>(); int len = queue.size(); for(int i = 0; i < len; i++) { TreeNode cur = queue.remove(); if(cur.left != null) queue.offer(cur.left); if(cur.right != null) queue.offer(cur.right); tmp.add(cur.val); } result.add(tmp); } Collections.reverse(result); return result; } }