刷题总结
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;
}
}
不知道以上的思路是什么玩意,到现在都没想明白
得出了一下的输出
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;
}
}