```java
//90. 子集 II
public List<List<Integer>> subsetsWithDup(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
Arrays.sort(nums);
boolean[] vis = new boolean[nums.length + 1];
dfs(nums, 0, vis, res, path);
return res;
}
public void dfs(int[] nums, int cur, boolean[] vis, List<List<Integer>> res, List<Integer> path) {
// res.add(new ArrayList<>(path));
// for(int i=cur; i<nums.length;i++){
// if(i!=cur&&nums[i]==nums[i-1]){
// continue;
// }
// path.add(nums[i]);
// dfs(nums,i+1,vis,res,path);
// path.remove(path.size()-1);
// }
if (cur == nums.length) {
res.add(new ArrayList<>(path));
System.out.println(path);
return;
}
path.add(nums[cur]);
vis[cur] = true;
dfs(nums, cur + 1, vis, res, path);
vis[cur] = false;
path.remove(path.size() - 1);
dfs(nums, cur + 1, vis, res, path);
}
//89. 格雷编码
public List<Integer> grayCode(int n) {
List<Integer> list = new ArrayList<>();
list.add(0);
for (int i = 1; i <= n; i++) {
int m = list.size();
for (int j = m - 1; j >= 0; j--) {
list.add(list.get(j) | (1 << (i - 1)));
}
}
return list;
}
//86. 分隔链表
public ListNode partition(ListNode head, int x) {
ListNode small = new ListNode(0);
ListNode large = new ListNode(0);
ListNode sh = small;
ListNode lh = large;
while (head != null) {
if (head.val < x) {
small.next = head;
small = small.next;
} else {
large.next = head;
large = large.next;
}
head = head.next;
}
large.next = null;
small.next = lh.next;
return sh.next;
}
//81、删除排序链表中的重复元素 I
public ListNode deleteDuplicates(ListNode head) {
if (head == null || head.next == null) {
return head;
}
ListNode pre = new ListNode(0, head);
ListNode cur = pre;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val == cur.next.next.val) {
int temp = cur.next.val;
cur = cur.next;
while (cur.next != null && cur.next.val == temp) {
cur.next = cur.next.next;
}
} else {
cur = cur.next;
}
}
return pre.next;
}
//82. 删除排序链表中的重复元素 II
public ListNode deleteDuplicates82(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode pre = new ListNode();
pre.next = head;
ListNode cur = pre;
while (cur.next != null && cur.next.next != null) {
if (cur.next.val != cur.next.next.val) {
cur = cur.next;
} else {
int x = cur.next.val;
while (cur.next != null && cur.next.val == x) {
cur.next = cur.next.next;
}
}
}
return pre.next;
}
//81. 搜索旋转排序数组 II
public boolean search(int[] nums, int target) {
int l = 0, r = nums.length - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[mid] == target)
return true;
if (nums[l] == nums[mid] && nums[mid] == nums[r]) {
l++;
r--;
} else if (nums[l] <= nums[mid]) {
if (nums[l] <= target && target <= nums[mid]) {
r = mid - 1;
} else {
l = mid + 1;
}
} else {
if (nums[mid] > target && target <= nums[nums.length - 1]) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return false;
}
//80. 删除有序数组中的重复项 II
public int removeDuplicates(int[] nums) {
int n = nums.length;
if (n <= 2) {
return n;
}
int slow = 2, fast = 2;
while (fast < n) {
if (nums[slow - 2] != nums[fast]) {
nums[slow] = nums[fast];
++slow;
}
++fast;
}
return slow;
}
//79、单词搜索
public boolean exist(char[][] board, String word) {
for (int i = 0; i < board.length; i++) {
for (int j = 0; j < board[0].length; j++) {
boolean[][] vis = new boolean[board.length][board[0].length];
if (dfs(board, i, j, word, 0, vis)) {
return true;
}
}
}
return false;
}
public boolean dfs(char[][] board, int x, int y, String word, int k, boolean[][] vis) {
if (x < 0 || y < 0 || x >= board.length || y >= board[0].length) {
return false;
}
if (!vis[x][y]) {
if (board[x][y] != word.charAt(k))
return false;
else if (k == word.length() - 1) {
System.out.println(k);
return true;
}
vis[x][y] = true;
boolean right = dfs(board, x + 1, y, word, k + 1, vis);
boolean left = dfs(board, x - 1, y, word, k + 1, vis);
boolean up = dfs(board, x, y + 1, word, k + 1, vis);
boolean down = dfs(board, x, y - 1, word, k + 1, vis);
if (right || left || up || down) {
return true;
}
vis[x][y] = false;
}
return false;
}
//78、子集
LinkedHashMap<List<Integer>, Integer> ans = new LinkedHashMap<>();
List<Integer> t = new ArrayList<>();
public List<List<Integer>> subsets(int[] nums) {
boolean[] vis = new boolean[nums.length + 1];
dfs(0, nums, vis);
List<List<Integer>> list = new ArrayList<>();
for (List<Integer> m : ans.keySet()) {
list.add(m);
}
return list;
}
public void dfs(int cur, int[] nums, boolean[] vis) {
if (cur == nums.length) {
ans.put(new ArrayList<Integer>(t), 1);
return;
}
for (int i = 0; i < 3; i++) {
if (vis[nums[i]])
continue;
vis[nums[i]] = true;
t.add(nums[i]);
dfs(cur + 1, nums, vis);
vis[nums[i]] = false;
t.remove(t.size() - 1);
dfs(cur + 1, nums, vis);
}
}
//77、组合
public List<List<Integer>> combine(int n, int k) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> list = new ArrayList<>();
boolean[] vis = new boolean[n + 1];
backtrace77(n, k, 1, res, list, vis);
return res;
}
public void backtrace77(int n, int k, int depth, List<List<Integer>> res, List<Integer> path, boolean[] vis) {
if (path.size() == k) {
res.add(new ArrayList<>(path));
return;
}
for (int i = depth; i <= n; i++) {
if (vis[i]) {
continue;
}
vis[i] = true;
path.add(i);
backtrace77(n, k, i + 1, res, path, vis);
path.remove(path.size() - 1);
vis[i] = false;
}
}
//75、颜色分类
//双指针
public void sortColors(int[] nums) {
int p0 = 0;
int p1 = 0;
int len = nums.length;
for (int i = 0; i < len; i++) {
if (nums[i] == 1) {
int temp = nums[p1];
nums[p1] = 1;
nums[i] = temp;
p1++;
} else if (nums[i] == 0) {
int temp = nums[p0];
nums[p0] = 0;
nums[i] = temp;
if (p0 < p1) {
temp = nums[p1];
nums[p1] = nums[i];
nums[i] = temp;
}
p0++;
p1++;
}
}
}
//单指针
public void sortColors_1(int[] nums) {
int len = nums.length;
int ptr = 0;
for (int i = 0; i < len; i++) {
if (nums[i] == 0) {
int temp = nums[ptr];
nums[ptr] = 0;
nums[i] = temp;
ptr++;
}
}
for (int i = ptr; i < len; i++) {
if (nums[i] == 1) {
int temp = nums[ptr];
nums[ptr] = 1;
nums[i] = temp;
ptr++;
}
}
}
//74. 搜索二维矩阵
public boolean searchMatrix(int[][] matrix, int target) {
int r = 0;
int mid = 0;
int posRow = binarySearchRow(target, matrix);
if (posRow < 0) {
return false;
}
return binarySearchCol(target, matrix, posRow);
}
int binarySearchRow(int target, int[][] nums) {
int l = -1;
int r = nums.length - 1;
while (l < r) {
int mid = (r - l + 1) / 2 + l;
if (nums[mid][0] == target) {
return mid;
}
if (nums[mid][0] > target) {
r = mid - 1;
}
if (nums[mid][0] < target) {
l = mid;
}
}
return l;
}
boolean binarySearchCol(int target, int[][] nums, int posRow) {
int l = 0;
int r = nums[0].length - 1;
while (l <= r) {
int mid = (l + r) / 2;
if (nums[posRow][mid] == target)
return true;
if (nums[posRow][mid] > target) {
r = mid - 1;
}
if (nums[posRow][mid] < target) {
l = mid + 1;
}
}
return false;
}
public boolean searchMatrix1(int[][] matrix, int target) {
int row = matrix.length;
int col = matrix[0].length;
int r = 0;
int c = 0;
if (row == 0 || col == 0)
return false;
if (target < matrix[0][0])
return false;
if (target > matrix[row - 1][col - 1])
return false;
for (int i = 0; i < row; i++) {
System.out.println(matrix[i][0]);
if (target > matrix[i][0]) {
r = i;
} else {
break;
}
}
for (int j = 0; j < col; j++) {
if (matrix[r][j] == target) {
return true;
}
}
return false;
}
//73、矩阵置0
public void setZeroes(int[][] matrix) {
//原地算法,只用o(1)的额外空间,或者很小的固定的空间
int row = matrix.length;
int col = matrix[0].length;
int flag_r = 0;
int flag_c = 0;
for (int i = 0; i < row; i++) {
if (matrix[i][0] == 0)
flag_r = 1;
}
for (int i = 0; i < col; i++) {
if (matrix[0][i] == 0)
flag_c = 1;
}
for (int i = 1; i < row; i++) {
for (int j = 1; j < col; j++) {
if (matrix[i][j] == 0) {
matrix[i][0] = matrix[0][j] = 0;
}
}
}
for (int i = 1; i < row; i++) {
for (int j = 1; j < col; j++) {
if (matrix[i][0] == 0 || matrix[0][j] == 0)
matrix[i][j] = 0;
}
}
if (flag_r == 1) {
for (int i = 0; i < row; i++) {
matrix[i][0] = 0;
}
}
if (flag_c == 1) {
for (int i = 0; i < col; i++) {
matrix[0][i] = 0;
}
}
}
//72、编辑距离
public int minDistance(String word1, String word2) {
return 0;
}
//71、简化路径
public String simplifyPath(String path) {
String[] str = path.split("/");
Deque<String> stack = new ArrayDeque<>();
for (int i = 0; i < str.length; i++) {
//System.out.println(str[i]);
if (str[i].equals(" ") || str[i].equals(""))
continue;
if (str[i].equals("."))
continue;
if (str[i].equals("..")) {
if (!stack.isEmpty()) {
stack.pop();
}
continue;
}
if (str[i].equals("/"))
continue;
stack.push(str[i]);
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("/");
while (!stack.isEmpty()) {
String temp = stack.peekLast();
stringBuilder.append(temp);
stringBuilder.append("/");
stack.removeLast();
}
if (stringBuilder.length() == 1) {
return stringBuilder.toString();
}
stringBuilder.deleteCharAt(stringBuilder.length() - 1);
return stringBuilder.toString();
}
//70、爬楼梯
public int climbStairs(int n) {
int[] floor = new int[50];
floor[0] = 0;
floor[1] = 1;
floor[2] = 2;
for (int i = 3; i <= n; i++) {
floor[i] = floor[i - 1] + floor[i - 2];
}
return floor[n];
}
//69、x的平方根
public int mySqrt(int x) {
if (x == 0)
return 0;
if (x == 1)
return 1;
for (int i = 0; i <= x / 2; i++) {
if ((long) i * i <= x && (long) (i + 1) * (i + 1) >= x) {
if ((long) i * i == x)
return i;
if ((long) (i + 1) * (i + 1) == x)
return i + 1;
return i;
}
}
return 0;
}
public int mySqrt1(int x) {
int l = 0, r = x;
int ans = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if ((long) mid * mid <= x) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}
//18、四数之和
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> res = new ArrayList<>();
List<Integer> path = new ArrayList<>();
int ans = 0;
Arrays.sort(nums);
dfs(nums, target, 0, path, res, ans);
return res;
}
public void dfs(int[] nums, int target, int begin, List<Integer> path, List<List<Integer>> res, int ans) {
if (path.size() == 4) {
if (ans == target) {
res.add(new ArrayList<>(path));
}
return;
}
for (int i = begin; i < nums.length; i++) {
if (nums.length - i < 4 - path.size())
return;
if (i > begin && nums[i] == nums[i - 1])
continue;
if (i < nums.length - 1 && ans + nums[i] + (3 - path.size()) * nums[i + 1] > target)
return;
if (i < nums.length - 1 && ans + nums[i] + (3 - path.size()) * nums[nums.length - 1] < target)
continue;
ans += nums[i];
path.add(nums[i]);
dfs(nums, target, i + 1, path, res, ans);
ans -= nums[i];
path.remove(path.size() - 1);
}
}
//17. 电话号码的字母组合
Map<Character, String> phoneMap = new HashMap<>() {{
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
}};
public List<String> letterCombinations(String digits) {
StringBuilder str = new StringBuilder();
StringBuilder path = new StringBuilder();
List<String> res = new ArrayList<>();
if (digits.equals(""))
return res;
traceback(path, res, 0, digits);
return res;
}
public void traceback(StringBuilder path, List<String> res, int depth, String dights) {
if (depth == dights.length()) {
res.add(path.toString());
} else {
char c = dights.charAt(depth);
String letter = phoneMap.get(c);
for (int i = 0; i < letter.length(); i++) {
path.append(letter.charAt(i));
traceback(path, res, depth + 1, dights);
path.deleteCharAt(depth);
}
}
}
//16、最接近的三数之和
public int threeSumClosest(int[] nums, int target) {
int ans = 99999999;
if (nums.length == 0)
return 0;
if (nums.length == 1)
return nums[0];
Arrays.sort(nums);
for (int first = 0; first < nums.length; first++) {
int third = nums.length - 1;
int second = first + 1;
while (second < third) {
int sum = nums[first] + nums[second] + nums[third];
if (sum == target)
return sum;
if (Math.abs(sum - target) < Math.abs((ans - target))) {
ans = sum;
}
if (sum > target) {
int k = third - 1;
while (second < k && nums[third] == nums[k]) {
k--;
}
third = k;
} else {
int v = second + 1;
while (v < third && nums[v] == nums[second]) {
v++;
}
second = v;
}
}
}
return ans;
}
//37、解数独
List<int[]> spaces = new ArrayList<>();
private boolean valid = false;
boolean[][] row = new boolean[9][9];
boolean[][] col = new boolean[9][9];
boolean[][][] sub = new boolean[3][3][9];
public void solveSudoku(char[][] board) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] != '.') {
int c = board[i][j] - '0' - 1;
row[i][c] = true;
col[j][c] = true;
sub[i / 3][j / 3][c] = true;
} else {
spaces.add(new int[]{i, j});
}
}
}
dfs(board, 0);
}
public void dfs(char[][] board, int pos) {
if (pos == spaces.size()) {
valid = true;
return;
}
int i = spaces.get(pos)[0];
int j = spaces.get(pos)[1];
for (int digit = 0; digit < 9 && !valid; digit++) {
if (!row[i][digit] && !col[j][digit] && !sub[i / 3][j / 3][digit]) {
row[i][digit] = col[j][digit] = sub[i / 3][j / 3][digit] = true;
board[i][j] = (char) (digit + '0' + 1);
dfs(board, pos + 1);
row[i][digit] = col[j][digit] = sub[i / 3][j / 3][digit] = false;
}
}
}
//36、有效的数独
public boolean isValidSudoku(char[][] board) {
int len = board.length;
int[][] row = new int[len][len];
int[][] col = new int[len][len];
int[][][] sub = new int[len][len][9];
for (int i = 0; i < len; i++) {
for (int j = 0; j < len; j++) {
if (board[i][j] != '.') {
int c = board[i][j] - '0' - 1;
row[i][c]++;
col[j][c]++;
sub[i / 3][j / 3][c]++;
if (row[i][c] > 1 || col[j][c] > 1 || sub[i / 3][j / 3][c] > 1) {
return false;
}
}
}
}
return true;
}
//84. 柱状图中最大的矩形
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if (len == 0)
return 0;
if (len == 1) {
return heights[0];
}
int area = 0;
int[] newHeights = new int[len + 2];
for (int i = 0; i < len; i++) {
newHeights[i + 1] = heights[i];
}
len += 2;
heights = newHeights;
Deque<Integer> stack = new ArrayDeque<>();
stack.addLast(0);
for (int i = 1; i < len; i++) {
while (heights[stack.peekLast()] > heights[i]) {
int height = heights[stack.removeLast()];
int width = i - stack.peekLast() - 1;
area = Math.max(area, height * width);
}
stack.addLast(i);
}
return area;
}
//15、三数之和
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new ArrayList<>();
Arrays.sort(nums);
int second = 0;
int third = 0;
for (int first = 0; first < nums.length; first++) {
if (first > 0 && nums[first] == nums[first - 1])
continue;
third = nums.length - 1;
int target = -nums[first];
for (second = first + 1; second < nums.length; second++) {
if (second > first + 1 && nums[second] == nums[second - 1])
continue;
while (second < third && nums[second] + nums[third] > target) {
third--;
}
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> path = new ArrayList<>();
path.add(nums[first]);
path.add(nums[second]);
path.add(nums[third]);
res.add(path);
}
}
}
return res;
}
//14、最长公共前缀
public String longestCommonPrefix(String[] strs) {
int row = strs.length;
if (row == 1)
return strs[0];
if (row == 0)
return null;
int col = 99999999;
for (int i = 0; i < row; i++) {
col = Math.min(col, strs[i].length());
}
StringBuilder stringBuilder = new StringBuilder();
for (int j = 0; j < col; j++) {
char ch = strs[0].charAt(j);
for (int i = 1; i < row; i++) {
if (strs[i].charAt(j) != ch) {
return stringBuilder.toString();
}
if (i == row - 1) {
stringBuilder.append(ch);
}
}
}
return stringBuilder.toString();
}
//10. 正则表达式匹配
public boolean isMatch(String s, String p) {
int m = s.length();
int n = p.length();
boolean[][] f = new boolean[m + 1][n + 1];
f[0][0] = true;
for (int i = 0; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (p.charAt(j - 1) == '*') {
f[i][j] = f[i][j - 2];
if (matches(s, p, i, j - 1)) {
f[i][j] = f[i][j] || f[i - 1][j];
}
} else {
if (matches(s, p, i, j)) {
f[i][j] = f[i - 1][j - 1];
}
}
}
}
return f[m][n];
}
public boolean matches(String s, String p, int i, int j) {
if (i == 0)
return false;
if (p.charAt(j - 1) == '.')
return true;
if (s.charAt(i - 1) == p.charAt(j - 1))
return true;
return false;
}
//9、回文数
public boolean isPalindrome(int x) {
String str = Integer.toString(x);
int len = str.length();
int i = 0, j = len - 1;
while (i <= j) {
if (str.charAt(i) == str.charAt(j)) {
i++;
j--;
} else
return false;
}
return true;
}
//13、罗马数字转整数
public int romanToInt(String s) {
Map<Character, Integer> symbolValues = new HashMap<Character, Integer>() {{
put('I', 1);
put('V', 5);
put('X', 10);
put('L', 50);
put('C', 100);
put('D', 500);
put('M', 1000);
}};
int ans = 0;
int len = s.length();
for (int i = 0; i < len; i++) {
int value = symbolValues.get(s.charAt(i));
if (i < len - 1 && value < symbolValues.get(s.charAt(i + 1))) {
ans -= value;
} else {
ans += value;
}
}
return ans;
}
//12、整数转罗马数字
public String intToRoman(int num) {
String[] thousands = {"", "M", "MM", "MMM"};
String[] hundreds = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
String[] tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
String[] ones = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
StringBuffer roman = new StringBuffer();
roman.append(thousands[num / 1000]);
roman.append(hundreds[num % 1000 / 100]);
roman.append(tens[num % 100 / 10]);
roman.append(ones[num % 10]);
return roman.toString();
}
//11. 盛最多水的容器
public int maxArea(int[] height) {
int len = height.length;
int i = 0, j = len - 1;
int ans = 0;
while (i <= j) {
int h = Math.min(height[i], height[j]);
ans = Math.max(ans, h * (j - i));
if (height[j] < height[i]) {
j--;
} else {
i++;
}
}
return ans;
}
//8、字符串转换整数 (atoi)
public int myAtoi(String str) {
int res = 0;
int len = str.length();
char[] charArray = str.toCharArray();
int index = 0;
while (index < len && charArray[index] == ' ')
index++;
if (index == len)
return 0;
int sign = 1;
char firstChar = charArray[index];
if (firstChar == '+') {
index++;
} else {
if (firstChar == '-') {
index++;
sign = -1;
}
}
while (index < len) {
char currentArray = charArray[index];
if (currentArray > '9' || currentArray < '0')
break;
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && (currentArray - '0') > Integer.MAX_VALUE % 10)) {
return Integer.MAX_VALUE;
}
if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && (currentArray - '0') > -(Integer.MIN_VALUE % 10))) {
return Integer.MIN_VALUE;
}
res = res * 10 + sign * (currentArray - '0');
index++;
}
return res;
}
public int trap(int[] height) {
int len = height.length;
int ans = 0;
int[] left = new int[len];
int[] right = new int[len];
left[0] = height[0];
for (int i = 1; i < len; i++) {
left[i] = Math.max(left[i - 1], height[i]);
}
right[len - 1] = height[len - 1];
for (int i = len - 2; i >= 0; i--) {
right[i] = Math.max(right[i + 1], height[i]);
}
for (int i = 1; i < len - 1; i++) {
ans += Math.min(left[i], right[i]) - height[i];
}
return ans;
}
//42. 接雨水
public int trap1(int[] height) {
//暴力解法
int ans = 0;
for (int i = 0; i < height.length; i++) {
int l = 0;
int r = 0;
for (int j = i; j >= 0; j--) {
l = Math.max(l, height[j]);
}
for (int j = i; j < height.length; j++) {
r = Math.max(r, height[j]);
}
ans += Math.min(l, r) - height[i];
}
return ans;
}
//7.整数反转
public int reverse(int x) {
//最大的32位整数是2147483647
int res = 0;
int temp = 0;
while (x != 0) {
temp = x % 10;
if (res > 214748364 || (res == 214748364 && temp == 7)) {
return 0;
}
if (res < -214748364 || (res == -214748364 && temp == 7)) {
return 0;
}
res = res * 10 + temp;
x /= 10;
}
return res;
}
//6. Z 字形变换
public String convert1(String s, int numRows) {
System.out.println(s);
char[][] ch = new char[numRows][1000];
int k = 0;
int i = 0, j = 0;
while (k < s.length()) {
if (i == 0) {
while (i < numRows && k < s.length()) {
ch[i++][j] = s.charAt(k++);
}
}
if (i == numRows) {
i--;
while (i > 0 && k < s.length())
ch[i--][j++] = s.charAt(k++);
}
}
StringBuilder stringBuilder = new StringBuilder();
for (int t = 0; t < j; t++) {
for (i = 0; i < numRows; i++) {
if (ch[i][t] != ' ') {
System.out.println(ch[i][t]);
}
}
}
return stringBuilder.toString();
}
public String convert(String s, int numRows) {
int n = s.length(), r = numRows;
if (r == 1 || r >= n) {
return s;
}
int t = r * 2 - 2;
int c = (n + t - 1) / t * (r - 1);
char[][] mat = new char[r][c];
for (int i = 0, x = 0, y = 0; i < n; ++i) {
mat[x][y] = s.charAt(i);
if (i % t < r - 1) {
++x; // 向下移动
} else {
--x;
++y; // 向右上移动
}
}
StringBuffer ans = new StringBuffer();
for (char[] row : mat) {
for (char ch : row) {
if (ch != 0) {
ans.append(ch);
}
}
}
return ans.toString();
}
//5. 最长回文子串
public String longestPalindrome(String s) {
if (s.length() == 1 || s.equals(" "))
return s;
int len = s.length();
boolean[][] dp = new boolean[len][len];
int begin = 0;
int maxLen = 1;
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
for (int l = 2; l <= len; l++) {
for (int i = 0; i < len; i++) {
int j = l + i - 1;
if (j >= len) {
break;
}
if (s.charAt(i) != s.charAt(j)) {
dp[i][j] = false;
} else {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
}
if (dp[i][j] && j - i + 1 > maxLen) {
maxLen = j - i + 1;
begin = i;
}
}
}
return s.substring(begin, begin + maxLen);
}
//寻找两个正序数组的中位数
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int len1 = nums1.length;
int len2 = nums2.length;
int i = 0, j = 0;
int[] arr = new int[len1 + len2];
int k = 0;
double ans = 0;
while (i < len1 && j < len2) {
if (nums1[i] <= nums2[j]) {
arr[k++] = nums1[i];
i++;
} else {
arr[k++] = nums2[j];
j++;
}
}
while (i < len1) {
arr[k++] = nums1[i];
i++;
}
while (j < len2) {
arr[k++] = nums2[j];
j++;
}
if ((len1 + len2) % 2 == 0) {
ans = 1.0 * (arr[(len1 + len2) / 2 - 1] + arr[(len1 + len2) / 2]) / 2;
} else {
ans = 1.0 * (arr[(len1 + len2) / 2]);
}
return ans;
}
//得分情况
/***
* 一张100分试卷,判断10*2,单选10*4,多选5*8,从前往后做,错三个离场,
* 给定一个成绩,问有多少种情况
* */
public void gradeDivider() {
Scanner sc = new Scanner(System.in);
int grade = 100;
int count = 0;
for (int i = 0; i <= 3; i++) {
for (int j = 0; j <= 3; j++) {
for (int k = 0; k <= 3; k++) {
if ((i + j + k) != 3) {
continue;
} else {
if ((10 - i) * 2 + (10 - j) * 4 + (5 - k) * 8 == grade) {
count++;
}
}
System.out.println(i + " " + j + " " + k);
System.out.println("-----------------");
}
}
}
}
//力扣 3、无重复字符的最长字串
public int lengthOfLongestSubstring(String s) {
int l = 0;
int maxLen = 0;
if (s.equals(" ")) {
return 1;
}
if (s.length() == 1) {
return 1;
}
HashMap<Character, Integer> map = new HashMap<>();
int i = 0;
for (i = 0; i < s.length(); i++) {
if (map.get(s.charAt(i)) == null)
map.put(s.charAt(i), i);
else {
l = Math.max(l, map.get(s.charAt(i)) + 1);
map.put(s.charAt(i), i);
}
maxLen = Math.max(maxLen, i - l + 1);
}
return maxLen;
}
//两数相加
/****
* 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
*
* 请你将两个数相加,并以相同形式返回一个表示和的链表。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode-cn.com/problems/add-two-numbers
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode p1 = l1;
ListNode p2 = l2;
int num1;
int sum1 = 0;
int count = 0;
int temp = 0;
int sum = 0;
ListNode listNode = new ListNode();
sum = (p1.val + p2.val);
temp = sum / 10;
listNode.val = sum % 10;
ListNode t = listNode;
p1 = p1.next;
p2 = p2.next;
while (p1 != null && p2 != null) {
ListNode p = new ListNode();
sum = p1.val + p2.val;
p.val = (sum + temp) % 10;
temp = (sum + temp) / 10;
t.next = p;
t = p;
p1 = p1.next;
p2 = p2.next;
}
while (p1 != null) {
ListNode p = new ListNode();
sum = (p1.val + temp);
temp = sum / 10;
p.val = sum % 10;
t.next = p;
t = p;
p1 = p1.next;
}
while (p2 != null) {
ListNode p = new ListNode();
sum = p2.val + temp;
temp = sum / 10;
p.val = sum % 10;
t.next = p;
t = p;
p2 = p2.next;
}
if (temp != 0) {
ListNode p = new ListNode();
p.val = temp;
t.next = p;
}
return listNode;
}
//HJ4 字符串分隔
/*
•输入一个字符串,请按长度为8拆分每个输入字符串并进行输出;
•长度不是8整数倍的字符串请在后面补数字0,空字符串不处理。
**/
public void spiltStr() {
Scanner sc = new Scanner(System.in);
String str = sc.next();
if (str.length() == 8) {
System.out.println(str);
}
if (str.length() < 8) {
StringBuilder s = new StringBuilder();
s.append(str);
for (int i = str.length(); i < 8; i++) {
s.append(0);
}
System.out.println(s.toString());
return;
}
int len = str.length();
int temp = 0;
if (len % 8 == 0) {
temp = len / 8;
}
int i = 0;
for (i = 0; i <= temp * 8; i += 8) {
String strTemp = str.substring(i, i + 8);
System.out.println(strTemp);
}
if (i == len) {
return;
} else {
StringBuilder s = new StringBuilder();
String strTemp = str.substring(i, len);
s.append(strTemp);
for (; i < len; i++) {
s.append(0);
}
System.out.println(s.toString());
}
}
//HJ2 计算某字符出现次数
public int countChar() {
Scanner sc = new Scanner(System.in);
String str = sc.next();
char c = sc.next().charAt(0);
int count = 0;
for (int i = 0; i < str.length(); i++) {
if (str.charAt(i) == c) {
count++;
}
}
return count;
}
//字符串最后一个字符
/*计算字符串最后一个单词的长度,单词以空格隔开,字符串长度小于5000。(注:字符串末尾不以空格为结尾)
* */
public int lastLength() {
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
char[] ch = str.toCharArray();
int len = str.length();
System.out.println(str);
int count = 0;
for (int i = len - 1; i >= 0; i--) {
if (ch[i] == ' ') {
return count;
} else count++;
}
return count;
}
//力扣 67、二进制求和
/*给你两个二进制字符串,返回它们的和(用二进制表示)。
输入为 非空 字符串且只包含数字 1 和 0。
* */
public String addBinary(String a, String b) {
StringBuilder ans = new StringBuilder();
int ca = 0;
for (int i = a.length() - 1, j = b.length() - 1; i >= 0 || j >= 0; i--, j--) {
int sum = ca;
sum += i >= 0 ? a.charAt(i) - '0' : 0;
sum += j >= 0 ? b.charAt(j) - '0' : 0;
ans.append(sum % 2);
ca = sum / 2;
}
ans.append(ca == 1 ? ca : "");
return ans.reverse().toString();
}
public String addBinary1(String a, String b) {
if (a.equals("") || b.equals(" ")) {
return null;
}
int lena = a.length();
int lenb = b.length();
int minLen = Math.max(lena, lenb);
int temp = 0;
StringBuilder sa = new StringBuilder();
StringBuilder sb = new StringBuilder();
for (int i = lena - 1; i >= 0; i--) {
sa.append(a.charAt(i));
}
for (int i = lenb - 1; i >= 0; i--) {
sb.append(b.charAt(i));
}
StringBuilder s = new StringBuilder();
int i = 0;
for (i = 0; i < minLen; i++) {
s.append((sa.charAt(i) - '0' + sb.charAt(i) - '0' + temp) % 2);
temp = (sa.charAt(i) - '0' + sb.charAt(i) - '0' + temp) / 2;
}
while (i < lena) {
s.append((sa.charAt(i) + temp) % 2);
temp = (sa.charAt(i) + temp) / 2;
i++;
}
while (i < lenb) {
s.append((sb.charAt(i) + temp) % 2);
temp = (sb.charAt(i) + temp) / 2;
i++;
}
if (temp == 1) {
s.append(temp);
}
String str = s.reverse().toString();
return str;
}
//力扣 66、加1
/*给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。
* */
public int[] plusOne(int[] digits) {
if (digits[digits.length - 1] < 9) {
digits[digits.length - 1] += 1;
return digits;
} else {
StringBuilder s = new StringBuilder();
StringBuilder res = new StringBuilder();
for (int i = digits.length - 1; i >= 0; i--) {
s.append(digits[i]);
}
String str = s.toString();
int temp = 0;
res.append((str.charAt(0) - '0' + 1) % 10);
temp = (str.charAt(0) - '0' + 1) / 10;
for (int i = 1; i < digits.length; i++) {
res.append((str.charAt(i) - '0' + temp) % 10);
temp = (str.charAt(i) - '0' + temp) / 10;
}
if (temp == 1) {
res.append(temp);
}
str = res.reverse().toString();
int[] ans = new int[res.length()];
for (int i = 0; i < str.length(); i++) {
ans[i] = str.charAt(i) - '0';
}
return ans;
}
}
//用两个线程交替打印奇偶数
private int count = 0;
private final Object lock = new Object();
public void turning() throws InterruptedException {
Thread even = new Thread(() -> {
while (count <= 100) {
synchronized (lock) {
System.out.println("偶数: " + count++);
lock.notifyAll();
try {
// 如果还没有结束,则让出当前的锁并休眠
if (count <= 100) {
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thread odd = new Thread(() -> {
while (count <= 100) {
synchronized (lock) {
System.out.println("奇数: " + count++);
lock.notifyAll();
try {
// 如果还没有结束,则让出当前的锁并休眠
if (count <= 100) {
lock.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
even.start();
// 确保偶数线程线先获取到锁
Thread.sleep(1);
odd.start();
}
//有效数字
public boolean isNumber(String s) {
if (null == s || s.length() == 0) {
return false;
}
//防止多个.或者e的情况
if (s.indexOf(".") != s.lastIndexOf(".") || s.indexOf("e") != s.lastIndexOf("e")) {
return false;
}
if (s.contains(".")) {
if (s.length() == 1) {
return false;
}
String[] splitArr = s.split("\\.");
//防止.+的情况
if (splitArr.length == 1 && splitArr[0].length() == 1 && (splitArr[0].contains("+") || splitArr[0].contains("-"))) {
return false;
}
//防止.e的情况
if (splitArr.length == 2 && splitArr[0].length() == 0 && (splitArr[1].startsWith("E") || splitArr[1].startsWith("e"))) {
return false;
}
//防止e为在小数点之前的情况
if (splitArr[0].contains("e") || splitArr[0].contains("E")) {
return false;
}
//小数点分割出的每一段,都去做校验
for (String str : splitArr) {
if (!check(str, true)) {
return false;
}
count++;
}
} else {
if (!check(s, false)) {
return false;
}
}
return true;
}
//校验方法,能同时校验小数点分割的情况、没有小数点的情况
//flag作为是否产生小数点分割的标志位
public boolean check(String s, boolean flag) {
if (count == 0 && (s.startsWith("e") || s.startsWith("E"))) {
return false;
}
boolean eFlag = s.contains("e");
boolean EFlag = s.contains("E");
if (eFlag || EFlag) {
String[] split = null;
if (eFlag) {
split = s.split("e");
} else {
split = s.split("E");
}
if (split.length != 2) {
return false;
}
for (String str : split) {
boolean symbolFlag = false;
if (str.startsWith("+") || str.startsWith("-")) {
symbolFlag = true;
}
int i = 0;
if (symbolFlag) {
i++;
}
for (; i < str.length(); i++) {
char charAt = str.charAt(i);
if (charAt < 48 || charAt > 57) {
return false;
}
}
//校验仅有单符号的情景,比如4e+
if (symbolFlag && str.length() == 1) {
return false;
}
}
} else {
boolean symbolFlag = false;
if (s.startsWith("+") || s.startsWith("-")) {
symbolFlag = true;
}
//如果这是根据小数点分割的第二个字符串,且以+号开头,则直接返回false。类似1.+56
if (count == 1 && symbolFlag && flag) {
return false;
}
int i = 0;
if (symbolFlag) {
i++;
}
//根据小数点,e分割完了之后,字符串片段中,不是开头的部分只能为数字,否则都是无效的
for (; i < s.length(); i++) {
char charAt = s.charAt(i);
if (charAt < 48 || charAt > 57) {
return false;
}
}
}
return true;
}
//剑指 Offer II 095. 最长公共子序列 力扣 阿里
public int longestCommonSubsequence(String text1, String text2) {
int res;
int len1 = text1.length();
int len2 = text2.length();
int[][] dp = new int[len1 + 1][len2 + 1];
for (int i = 1; i <= len1; i++) {
char ch1 = text1.charAt(i - 1);
for (int j = 1; j <= len2; j++) {
char ch2 = text2.charAt(j - 1);
if (ch1 == ch2) {
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];
}
//剑指 Offer 27. 二叉树的镜像 力扣 阿里
public TreeNode mirrorTree(TreeNode root) {
if (root == null) {
return null;
}
TreeNode left = mirrorTree(root.left);
TreeNode right = mirrorTree(root.right);
root.left = right;
root.right = left;
return root;
}
//力扣 最小覆盖字串 滑动窗口
public String minWindow(String s, String t) {
String ans = null;
if (s == null || s.length() == 0 || t == null || t.length() == 0) {
return " ";
}
int lens = s.length();
int lent = t.length();
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < lent; i++) {
map.put(s.charAt(i), map.getOrDefault(s.charAt(i), 0) + 1);
}
int l = 0, r = 0, count = 0;
for (int i = 0; i < lent; i++) {
}
return ans;
}
//力扣 串联所有单词的子串 滑动窗口
public List<Integer> findSubstring(String s, String[] words) {
List<Integer> res = new ArrayList<>();
int one_word = words[0].length();
int word_num = words.length;
int all_len = one_word * word_num;
int len = s.length();
if (s == null || s.length() == 0 || words == null || words.length == 0)
return res;
HashMap<String, Integer> map = new HashMap<>();
for (String word : words) {
map.put(word, map.getOrDefault(word, 0) + 1);
}
for (int i = 0; i < one_word; i++) {
HashMap<String, Integer> tmp_map = new HashMap<>();
int l = i, r = i, count = 0;
while (r + one_word <= len) {
String w = s.substring(r, r + one_word);
r += one_word;
if (!map.containsKey(w)) {
count = 0;
l = r;
tmp_map.clear();
} else {
tmp_map.put(w, tmp_map.getOrDefault(w, 0) + 1);
count++;
while (tmp_map.getOrDefault(w, 0) > map.getOrDefault(w, 0)) {
String tmp_w = s.substring(l, l + one_word);
count--;
tmp_map.put(tmp_w, tmp_map.getOrDefault(tmp_w, 0) - 1);
l += one_word;
}
if (count == word_num) {
res.add(l);
}
}
}
}
return res;
}
//力扣 无重复字符的最长字串 滑动窗口
public int lengthOfLongestSubstring1(String s) {
int len = s.length();
int max = 0;
int left = 0;
HashMap<Character, Integer> map = new HashMap<>();
for (int i = 0; i < len; i++) {
if (map.containsKey(s.charAt(i))) {
left = Math.max(left, map.get(s.charAt(i)) + 1);
}
map.put(s.charAt(i), i);
max = Math.max(max, i - left + 1);
}
return max;
}
// 字节 ZJ2
public static String solve2(long n, long k, long d1, long d2) {
long left;
//第一种情况
long m1 = k + 2 * d1 + d2;
if (m1 >= 0 && m1 % 3 == 0) {
left = (n - k) - (2 * d1 + d2);
if (left >= 0 && left % 3 == 0) {
return "yes";
}
}
//第二种情况
long m2 = k + 2 * d1 - d2;
if (m2 >= 0 && m2 % 3 == 0) {
if (d1 >= d2) {
left = (n - k) - (2 * d1 - d2);
} else {
left = (n - k) - (2 * d2 - d1);
}
if (left >= 0 && left % 3 == 0) {
return "yes";
}
}
//第三种情况
long m3 = k - 2 * d1 + d2;
if (m3 >= 0 && m3 % 3 == 0) {
left = (n - k) - (d1 + d2);
if (left >= 0 && left % 3 == 0) {
return "yes";
}
}
//第四种情况
long m4 = k - (2 * d1 + d2);
if (m4 >= 0 && m4 % 3 == 0) {
left = (n - k) - (d1 + 2 * d2);
if (left >= 0 && left % 3 == 0) {
return "yes";
}
}
return "no";
}
// 力扣 最小路径和
public int minPathSum(int[][] grid) {
int m = grid.length;
int n = grid[0].length;
int[][] dp = new int[m][n];//dp数组用来保存到达dp[i][j]的最小路径和
dp[0][0] = grid[0][0];
//初始化边界问题
for (int i = 1; i < m; i++) {
dp[i][0] = dp[i - 1][0] + grid[i][0];
}
for (int j = 1; j < n; j++) {
dp[0][j] = dp[0][j - 1] + grid[0][j];
}
//求每一步的最小路径之和
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = Math.min(dp[i - 1][j] + grid[i][j], dp[i][j - 1] + grid[i][j]);
}
}
return dp[m - 1][n - 1];
}
//不同路径II 网格中间加入了障碍物
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
//求出网格的行和列
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] path = new int[m][n];
//下面两个for循环是处理边界的
for (int i = 0; i < m; i++) {
if (obstacleGrid[i][0] == 1) {
for (int j = i; j < m; j++) {
path[j][0] = 0;
}
break;
} else path[i][0] = 1;
}
for (int i = 0; i < n; i++) {
if (obstacleGrid[0][i] == 1) {
for (int j = i; j < n; j++) {
path[0][j] = 0;
}
break;
} else
path[0][i] = 1;
}
//这个for循环是处理网格除了边界的
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1) {
path[i][j] = 0;
}
}
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 1)
path[i][j] = 0;
else
path[i][j] = path[i - 1][j] + path[i][j - 1];
}
}
return path[m - 1][n - 1];
}
//不同路径(动态规划)
public int uniquePaths(int m, int n) {
int[][] path = new int[m][n];//path[i][j]代表走到i,j位置有多少种路径
//初始化path数组,0行的所有列和0列的所有行都只有一种方案
for (int i = 0; i < m; i++) {
path[i][0] = 1;
}
for (int i = 0; i < n; i++) {
path[0][i] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
path[i][j] = path[i - 1][j] + path[i][j - 1];
}
}
return path[m - 1][n - 1];
}
public String getPermutation(int n, int k) {
this.n = n;
this.k = k;
calculateFactorial(n);
used = new boolean[n + 1];
Arrays.fill(used, false);
StringBuilder path = new StringBuilder();
dfs(0, path);
return path.toString();
}
//回溯+剪枝
public void dfs(int index, StringBuilder path) {
if (index == n) {
return;
}
int count = factorial[n - 1 - index];
for (int i = 1; i <= n; i++) {
if (used[i]) {
continue;
}
if (k > count) {
k -= count;
continue;
}
path.append(i);
used[i] = true;
dfs(index + 1, path);
return;
}
}
//计算阶乘数组
public void calculateFactorial(int n) {
factorial = new int[n + 1];
factorial[0] = 1;
for (int i = 1; i <= n; i++) {
factorial[i] = factorial[i - 1] * i;
}
}
public ListNode rotateRight(ListNode head, int k) {
int len;//链表长度
if (head == null) {
return null;
}
len = 1;
ListNode node = new ListNode();//这个node是为了计算链表的长度,并指向链表末尾
node = head;
while (node.next != null) {
len++;
node = node.next;
}
ListNode posNode;//旋转位置的链表节点
k %= len;
if (k == 0)
return head;
int pos = len - k;//旋转位置
ListNode preNode; //记录旋转节点的前一个节点
ListNode tempNode = head;//遍历链表的节点
preNode = tempNode;
int count = 0;
while (count != pos) {
count++;
preNode = tempNode;
tempNode = tempNode.next;
}
preNode.next = null;
node.next = head;
head = tempNode;
return head;
}
//飞地的数量
public int numEnclaves(int[][] grid) {
int res = 0;
int m = grid.length;
int n = grid[0].length;
boolean[][] vis = new boolean[m][n];
for (int i = 0; i < m; i++) {
dfs(grid, i, 0);
dfs(grid, i, n - 1);
}
for (int j = 1; j < n; j++) {
dfs(grid, 0, j);
dfs(grid, m - 1, j);
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 1 && vis[i][j] == false) {
res++;
}
}
}
return res;
}
public void dfs(int[][] grid, int x, int y) {
if (x < 0 || y < 0 || vis[x][y] || grid[x][y] == 0) {
return;
}
vis[x][y] = true;
dfs(grid, x + 1, y);
dfs(grid, x - 1, y);
dfs(grid, x, y + 1);
dfs(grid, x, y - 1);
}