list = new ArrayList<>();
for (int i = 0; i < weight.length; i++) {
weight[i][i] = 0;
int val = getVal(graph, i);
int x = getX(graph, i);
int y = getY(graph, i);
if (x == 0 || x == height - 1) {
list.add(i);
}
if (y == 0 || y == width - 1) {
list.add(i);
}
if (y < (width - 1) && i + 1 < total && getVal(graph, i + 1) <= val) {
weight[i][i + 1] = 1;
}
if (y != 0 && i - 1 >= 0 && getVal(graph, i - 1) <= val) {
weight[i][i - 1] = 1;
}
if (i + width < total && getVal(graph, i + width) <= val) {
weight[i][i + width] = 1;
}
if (i - width >= 0 && getVal(graph, i - width) <= val) {
weight[i][i - width] = 1;
}
}
int start = startX * width + startY;
int resultIndex = -1;
int resultLen = 256;
for (int i = 0; i < list.size(); i++) {
if (getVal(graph, list.get(i)) <= start) {
int len = resolve(start, list.get(i));
if (len < resultLen) {
resultLen = len;
resultIndex = list.get(i);
}
}
}
if (resultLen >= 256) {
System.out.print("-1 -1 -1");
return;
}
System.out.print(resultIndex / graph.length + " " + resultIndex % graph.length + " " + resultLen);
}
public static int resolve(int start, int end) {
if (start < 0 || end < 0 || start >= weight.length || end >= weight.length) {
return MAX;
}
boolean[] isVisited = new boolean[weight.length];
int[] d = new int[weight.length];
for (int i = 0; i < weight.length; i++) {
isVisited[i] = false;
d[i] = MAX;
}
d[start] = 0;
isVisited[start] = true;
int unVisitedNum = weight.length;
int index = start;
while (unVisitedNum > 0 && index != end) {
int min = MAX;
for (int i = 0; i < weight.length; i++) {
if (min > d[i] && !isVisited[i]) {
min = d[i];
index = i;
}
}
for (int i = 0; i < weight.length; i++) {
if (d[index] + weight[index][i] < d[i]) {
d[i] = d[index] + weight[index][i];
}
}
unVisitedNum--;
isVisited[index] = true;
}
return d[end];
}
}
================================================
FILE: src/其他/阿拉伯数字转中文/Main.java
================================================
package 其他.阿拉伯数字转中文;
/**
* @author yuanguangxin
*/
public class Main {
private static final char[] numArrays = {'零', '一', '二', '三', '四', '五', '六', '七', '八', '九'};
private static final char[] units = {'十', '百', '千', '万', '亿'};
private static final StringBuilder ans = new StringBuilder();
private static void intToChineseNum(int num) {
String s = String.valueOf(num);
char[] chars = s.toCharArray();
int n = chars.length;
// 只剩下一位时, 直接返回 numArrays 数组中对应的数字
if (n == 1) {
ans.append(numArrays[chars[0] - '0']);
// 如果 num 超过 5 位, 则先判断是否上亿, 然后将 num 拆分
} else if (n >= 5) {
n = n >= 9 ? 9 : 5;
int multi = (int) Math.pow(10, n - 1);
// div 表示 num 中上亿或上万的部分数值
int div = num / multi;
// mod 表示剩余的部分数值
int mod = num % multi;
// 对前一部分数值进行转换, 然后添加单位万/亿
intToChineseNum(div);
ans.append(n == 5 ? units[3] : units[4]);
String s1 = String.valueOf(div);
String s2 = String.valueOf(mod);
// 判断中间是否有 0
if (s.charAt(s1.length() - 1) == '0' || s2.length() < n - 1) ans.append("零");
// 转换剩余部分
intToChineseNum(mod);
// 如果 num 不超过 5 位, 处理过程与上面相似
} else {
int multi = (int) Math.pow(10, n - 1);
int div = num / multi;
int mod = num % multi;
ans.append(numArrays[div]).append(units[n - 2]);
if (mod != 0) {
if (String.valueOf(mod).length() < n - 1) {
ans.append("零");
}
intToChineseNum(mod);
}
}
}
}
================================================
FILE: src/分治法/q23_合并K个排序链表/ListNode.java
================================================
package 分治法.q23_合并K个排序链表;
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
================================================
FILE: src/分治法/q23_合并K个排序链表/Solution.java
================================================
package 分治法.q23_合并K个排序链表;
/**
* 做k-1次mergeTwoLists o(N*k) 可用分治法优化至o(N*log(k))) N为所有list的总节点数
*/
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
}
if (l2 == null) {
return l1;
}
ListNode head = new ListNode(Integer.MIN_VALUE);
head.next = l1;
ListNode pre = head;
while (l2 != null) {
ListNode t1 = pre.next;
ListNode t2 = l2.next;
while (l2.val > t1.val) {
if (t1.next == null) {
t1.next = l2;
return head.next;
} else {
pre = pre.next;
t1 = t1.next;
}
}
pre.next = l2;
l2.next = t1;
l2 = t2;
}
return head.next;
}
public ListNode mergeKLists(ListNode[] lists) {
if (lists.length == 0) {
return null;
}
if (lists.length == 1) {
return lists[0];
}
ListNode result = lists[0];
for (int i = 1; i < lists.length; i++) {
result = mergeTwoLists(result, lists[i]);
}
return result;
}
}
================================================
FILE: src/分治法/q33_搜索旋转排序数组/Solution.java
================================================
package 分治法.q33_搜索旋转排序数组;
/**
* 循环有序数组查找 二分法o(log(n))
*/
class Solution {
public int search(int[] nums, int target) {
return search(nums, 0, nums.length - 1, target);
}
private int search(int[] nums, int low, int high, int target) {
if (low > high) {
return -1;
}
int mid = (low + high) / 2;
if (nums[mid] == target) {
return mid;
}
//nums[mid] < nums[high]说明后半段有序
if (nums[mid] < nums[high]) {
//说明target在后半段
if (nums[mid] < target && target <= nums[high]) {
return search(nums, mid + 1, high, target);
}
return search(nums, low, mid - 1, target);
} else {
//后半段无序前半段有序,target在前半段
if (nums[low] <= target && target < nums[mid]) {
return search(nums, low, mid - 1, target);
}
return search(nums, mid + 1, high, target);
}
}
}
================================================
FILE: src/分治法/q34_在排序数组中查找元素的第一个和最后一个位置/Solution.java
================================================
package 分治法.q34_在排序数组中查找元素的第一个和最后一个位置;
/**
* 二分法 o(log(n))
*/
public class Solution {
public int[] searchRange(int[] nums, int target) {
if (nums == null || nums.length < 1) {
return new int[]{-1, -1};
}
int midIndex = find(0, nums.length - 1, nums, target);
int[] rs = new int[2];
rs[0] = midIndex;
rs[1] = midIndex;
if (midIndex == -1) {
return rs;
}
while (nums[rs[0]] == target && rs[0] > 0) {
int temp = find(0, rs[0] - 1, nums, target);
if (temp == -1) {
break;
} else {
rs[0] = temp;
}
}
while (nums[rs[1]] == target && rs[1] < nums.length - 1) {
int temp = find(rs[1] + 1, nums.length - 1, nums, target);
if (temp == -1) {
break;
} else {
rs[1] = temp;
}
}
return rs;
}
public int find(int beginIndex, int endIndex, int[] nums, int target) {
if (beginIndex == endIndex) {
if (nums[beginIndex] == target) {
return beginIndex;
} else {
return -1;
}
}
int mid = (endIndex - beginIndex) / 2 + beginIndex;
if (nums[mid] > target) {
return find(beginIndex, mid, nums, target);
} else if (nums[mid] < target) {
return find(mid + 1, endIndex, nums, target);
} else {
return mid;
}
}
public static void main(String[] args) {
new Solution().searchRange(new int[]{2, 2}, 2);
}
}
================================================
FILE: src/动态规划/q1143_最长公共子序列/Solution.java
================================================
package 动态规划.q1143_最长公共子序列;
/**
* 动态规划 dp[i + 1][j + 1] = Math.max(dp[i+1][j], dp[i][j+1]) o(m*n)
*
* 若题目为最长公共子串,则在c1,c2不相等时不做处理(赋值0),在遍历过程中记录最大值即可
*/
public class Solution {
public int longestCommonSubsequence(String text1, String text2) {
int m = text1.length();
int n = text2.length();
int[][] dp = new int[m + 1][n + 1];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
char c1 = text1.charAt(i);
char c2 = text2.charAt(j);
if (c1 == c2) {
dp[i + 1][j + 1] = dp[i][j] + 1;
} else {
dp[i + 1][j + 1] = Math.max(dp[i + 1][j], dp[i][j + 1]);
}
}
}
return dp[m][n];
}
/**
* 最长公共字串
*
* @param str1
* @param str2
* @return
*/
public static String longestCommonSubstring(String str1, String str2) {
int m = str1.length();
int n = str2.length();
int[][] dp = new int[m + 1][n + 1];
int maxLength = 0;
int endIndex = -1;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1] + 1;
if (dp[i][j] > maxLength) {
maxLength = dp[i][j];
endIndex = i - 1;
}
} else {
dp[i][j] = 0;
}
}
}
if (maxLength == 0) {
return "";
}
return str1.substring(endIndex - maxLength + 1, endIndex + 1);
}
}
================================================
FILE: src/动态规划/q118_杨辉三角/Solution.java
================================================
package 动态规划.q118_杨辉三角;
import java.util.ArrayList;
import java.util.List;
/**
* 找规律,动态规划 o(n^2)
*/
public class Solution {
public List> generate(int numRows) {
List> triangle = new ArrayList>();
if (numRows == 0) {
return triangle;
}
triangle.add(new ArrayList<>());
triangle.get(0).add(1);
for (int rowNum = 1; rowNum < numRows; rowNum++) {
List row = new ArrayList<>();
List prevRow = triangle.get(rowNum-1);
row.add(1);
for (int j = 1; j < rowNum; j++) {
row.add(prevRow.get(j-1) + prevRow.get(j));
}
row.add(1);
triangle.add(row);
}
return triangle;
}
}
================================================
FILE: src/动态规划/q1277_统计全为1的正方形子矩阵/Solution.java
================================================
package 动态规划.q1277_统计全为1的正方形子矩阵;
/**
* 动态规划 dp[i][j]表示 matrix[i][j] 这个点可以往左上构造的最大正方形的边长 o(n^2)
*/
public class Solution {
public int countSquares(int[][] matrix) {
if (matrix.length < 1) {
return 0;
}
int m = matrix.length;
int n = matrix[0].length;
int[][] dp = new int[m][n];
int rs = 0;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
dp[i][j] = 0;
} else {
if (i > 0 && j > 0) {
dp[i][j] = Math.min(Math.min(dp[i - 1][j], dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
} else {
dp[i][j] = 1;
}
rs += dp[i][j];
}
}
}
return rs;
}
public static void main(String[] args) {
new Solution().countSquares(new int[][]{{0, 1, 1, 1}, {1, 1, 1, 1}, {0, 1, 1, 1}});
}
}
================================================
FILE: src/动态规划/q300_最长上升子序列/Solution.java
================================================
package 动态规划.q300_最长上升子序列;
/**
* 动态规划 dp[i]表示以i索引下标结束的最长上升子序列 o(n*log(n))
*/
public class Solution {
public int lengthOfLIS(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
}
if (nums.length == 1) {
return 1;
}
int n = nums.length;
int[] dp = new int[n];
int rs = 0;
for (int i = 0; i < n; i++) {
dp[i] = 1;
int max = 0;
for (int j = i - 1; j >= 0; j--) {
if (nums[j] < nums[i] && dp[j] > max) {
max = dp[j];
}
}
dp[i] += max;
if (dp[i] > rs) {
rs = dp[i];
}
}
return rs;
}
}
================================================
FILE: src/动态规划/q53_最大子序和/f1/Solution.java
================================================
package 动态规划.q53_最大子序和.f1;
/**
* 贪心法 遍历一次 o(n)
*/
public class Solution {
public int maxSubArray(int[] nums) {
if (nums.length == 1) {
return nums[0];
}
int sum = nums[0];
int temp = sum;
for (int i = 1; i < nums.length; i++) {
temp = temp + nums[i];
if (temp >= sum) {
sum = temp;
} else if (temp < 0) {
temp = 0;
}
if (nums[i] > sum) {
temp = nums[i];
sum = nums[i];
}
}
return sum;
}
public static void main(String[] args) {
System.out.println(new Solution().maxSubArray(new int[]{-1, 1, 2, 1}));
}
}
================================================
FILE: src/动态规划/q53_最大子序和/f2/Solution.java
================================================
package 动态规划.q53_最大子序和.f2;
/**
* 动态规划 dp[i]表示以nums[i]结尾的最大子序和 o(n)
*/
public class Solution {
public int maxSubArray(int[] nums) {
int[] dp = new int[nums.length];
dp[0] = nums[0];
int rs = dp[0];
for (int i = 1; i < nums.length; i++) {
int temp = dp[i - 1] + nums[i];
dp[i] = Math.max(nums[i],temp);
rs = Math.max(rs, dp[i]);
}
return rs;
}
public static void main(String[] args) {
System.out.println(new Solution().maxSubArray(new int[]{-2}));
}
}
================================================
FILE: src/动态规划/q5_最长回文子串/f1/Solution.java
================================================
package 动态规划.q5_最长回文子串.f1;
/**
* o(n^2) 以每个字符为中心计算回文长度
*/
class Solution {
public String getPalindrome(String s, int index) {
String rs = "";
int sLen = s.length();
int i = index;
int j = index;
while (j < sLen) {
if (s.charAt(j) == s.charAt(index)) {
rs = rs + s.charAt(j);
j++;
} else {
break;
}
}
i--;
while (i >= 0 && j < sLen) {
if (s.charAt(i) == s.charAt(j)) {
rs = s.charAt(i) + rs;
rs = rs + s.charAt(i);
i--;
j++;
} else {
break;
}
}
return rs;
}
public String longestPalindrome(String s) {
int maxLen = -1;
String rs = "";
for (int i = 0; i < s.length(); i++) {
String t = getPalindrome(s, i);
if (t.length() > maxLen) {
maxLen = t.length();
rs = t;
}
}
return rs;
}
}
================================================
FILE: src/动态规划/q5_最长回文子串/f2/Solution.java
================================================
package 动态规划.q5_最长回文子串.f2;
/**
* 动态规划 o(n^2)
* 转移方程:字符串两边界值相等并且子字符串是回文字符串则该字符串是回文字符串
* dp数组含义:字符串s从i到j的索引子字符串是否是回文字符串
*/
public class Solution {
public String longestPalindrome(String s) {
int len = s.length();
if (len < 2) {
return s;
}
boolean[][] dp = new boolean[len][len];
for (int i = 0; i < len; i++) {
dp[i][i] = true;
}
int maxLen = 1;
int start = 0;
for (int j = 1; j < len; j++) {
for (int i = 0; i < j; i++) {
if (s.charAt(i) == s.charAt(j)) {
if (j - i < 3) {
dp[i][j] = true;
} else {
dp[i][j] = dp[i + 1][j - 1];
}
} else {
dp[i][j] = false;
}
if (dp[i][j]) {
int curLen = j - i + 1;
if (curLen > maxLen) {
maxLen = curLen;
start = i;
}
}
}
}
return s.substring(start, start + maxLen);
}
}
================================================
FILE: src/动态规划/q62_不同路径/Solution.java
================================================
package 动态规划.q62_不同路径;
/**
* 动态规划 dp[i][j]是到达i, j的最多路径 dp[i][j] = dp[i-1][j] + dp[i][j-1] o(m*n)
*/
public class Solution {
public int uniquePaths(int m, int n) {
if (m < 1 || n < 1) {
return 0;
}
int[][] dp = new int[m][n];
for (int i = 0; i < n; i++) {
dp[0][i] = 1;
}
for (int i = 0; i < m; i++) {
dp[i][0] = 1;
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
return dp[m - 1][n - 1];
}
}
================================================
FILE: src/动态规划/q64_最小路径和/Solution.java
================================================
package 动态规划.q64_最小路径和;
/**
* 动态规划 dp(j)=grid(i,j)+min(dp(j),dp(j+1)) o(m*n)
*/
public class Solution {
public int minPathSum(int[][] grid) {
int[] dp = new int[grid[0].length];
for (int i = grid.length - 1; i >= 0; i--) {
for (int j = grid[0].length - 1; j >= 0; j--) {
if (i == grid.length - 1 && j != grid[0].length - 1) {
dp[j] = grid[i][j] + dp[j + 1];
} else if (j == grid[0].length - 1 && i != grid.length - 1) {
dp[j] = grid[i][j] + dp[j];
} else if (j != grid[0].length - 1 && i != grid.length - 1) {
dp[j] = grid[i][j] + Math.min(dp[j], dp[j + 1]);
} else {
dp[j] = grid[i][j];
}
}
}
return dp[0];
}
}
================================================
FILE: src/动态规划/q70_爬楼梯/Solution.java
================================================
package 动态规划.q70_爬楼梯;
/**
* 动态规划 dp[i]表示到达第i阶的方法总数dp[i]=dp[i−1]+dp[i−2] o(n)
*/
public class Solution {
public int climbStairs(int n) {
if (n == 1) {
return 1;
}
int[] dp = new int[n + 1];
dp[1] = 1;
dp[2] = 2;
for (int i = 3; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
}
================================================
FILE: src/动态规划/q746_使用最小花费爬楼梯/Solution.java
================================================
package 动态规划.q746_使用最小花费爬楼梯;
/**
* 动态规划 o(n) f[i] = cost[i] + min(f[i+1], f[i+2])
*/
class Solution {
public int minCostClimbingStairs(int[] cost) {
int f1 = 0, f2 = 0;
for (int i = cost.length - 1; i >= 0; i--) {
int f0 = cost[i] + Math.min(f1, f2);
f2 = f1;
f1 = f0;
}
return Math.min(f1, f2);
}
public static void main(String[] args) {
int[] a = new int[]{0, 2, 2, 1};
System.out.println(new Solution().minCostClimbingStairs(a));
}
}
================================================
FILE: src/区间合并/q56_合并区间/Solution.java
================================================
package 区间合并.q56_合并区间;
import java.util.*;
/**
* 先根据start进行排序之后merge o(n*log(n))
*/
class Solution {
public int[][] merge(int[][] intervals) {
if(intervals.length <= 1){
return intervals;
}
Arrays.sort(intervals, Comparator.comparingInt(arr -> arr[0]));
int[] currInterval = intervals[0];
List resArr = new ArrayList<>();
resArr.add(currInterval);
for(int[] interval: intervals){
int currEnd = currInterval[1];
int nextBegin = interval[0];
int nextEnd = interval[1];
if(currEnd >= nextBegin){
currInterval[1] = Math.max(currEnd, nextEnd);
} else{
currInterval = interval;
resArr.add(currInterval);
}
}
return resArr.toArray(new int[resArr.size()][]);
}
}
================================================
FILE: src/双指针遍历/q11_盛最多水的容器/Solution.java
================================================
package 双指针遍历.q11_盛最多水的容器;
/**
* 双指针遍历 o(n)
*/
public class Solution {
public int maxArea(int[] height) {
if (height.length < 2) {
return 0;
}
int left = 0;
int right = height.length - 1;
int result = 0;
while (right > left) {
int c = (Math.min(height[right], height[left])) * (right - left);
if (c >= result) {
result = c;
}
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return result;
}
public static void main(String[] args) {
int[] a = new int[]{1, 8, 6, 2, 5, 4, 8, 3, 7};
System.out.println(new Solution().maxArea(a));
}
}
================================================
FILE: src/双指针遍历/q121_买卖股票的最佳时机/Solution.java
================================================
package 双指针遍历.q121_买卖股票的最佳时机;
/**
* 维护一个最低股价变量,同时维护当前收益o(n)
*/
class Solution {
public int maxProfit(int[] prices) {
int min = Integer.MAX_VALUE;
int money = 0;
for (int i = 0; i < prices.length; i++) {
if (prices[i] < min) {
min = prices[i];
}
if (prices[i] - min > money) {
money = prices[i] - min;
}
}
return money;
}
public static void main(String[] args) {
int[] a = new int[]{7, 1, 5, 3, 6, 4};
System.out.println(new Solution().maxProfit(a));
}
}
================================================
FILE: src/双指针遍历/q15_三数之和/Solution.java
================================================
package 双指针遍历.q15_三数之和;
import java.util.*;
/**
* 数组遍历 + 双指针遍历 o(n^2)
*/
class Solution {
public List> threeSum(int[] nums) {
List> rs = new ArrayList<>();
if (nums.length < 3) {
return rs;
}
Arrays.sort(nums);
if (nums[0] > 0) {
return rs;
}
for (int i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
if (sum == 0) {
List temp = new ArrayList<>();
temp.add(nums[i]);
temp.add(nums[left]);
temp.add(nums[right]);
rs.add(temp);
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
left++;
right--;
} else if (sum > 0) {
right--;
} else {
left++;
}
}
}
return rs;
}
}
================================================
FILE: src/双指针遍历/q16_最接近的三数之和/Solution.java
================================================
package 双指针遍历.q16_最接近的三数之和;
import java.util.Arrays;
/**
* q15类型题 数组遍历 + 双指针遍历 o(n^2)
*/
public class Solution {
public int threeSumClosest(int[] nums, int target) {
if (nums.length < 3) {
return 0;
}
Arrays.sort(nums);
int rs = nums[0] + nums[1] + nums[2];
for (int i = 0; i < nums.length - 2; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
int sum = nums[i] + nums[left] + nums[right];
int c = sum - target;
if (Math.abs(c) < Math.abs(rs - target)) {
rs = sum;
}
if (c == 0) {
return target;
} else if (c > 0) {
right--;
} else {
left++;
}
}
}
return rs;
}
public static void main(String[] args) {
int[] a = new int[]{-3, -2, -5, 3, -4};
System.out.println(new Solution().threeSumClosest(a, -1));
}
}
================================================
FILE: src/双指针遍历/q209_长度最小的子数组/Solution.java
================================================
package 双指针遍历.q209_长度最小的子数组;
/**
* 两个指针滑动窗口o(n)
*/
public class Solution {
public int minSubArrayLen(int s, int[] nums) {
int sum = 0;
int i = 0;
int k = 0;
int min = Integer.MAX_VALUE;
while (true) {
if (k == nums.length && i == nums.length) {
break;
}
if (sum < s) {
if (k == nums.length) {
break;
}
sum += nums[k];
k++;
} else {
min = Math.min(k - i, min);
sum -= nums[i];
i++;
}
}
return min == Integer.MAX_VALUE ? 0 : min;
}
}
================================================
FILE: src/双指针遍历/q26_删除排序数组中的重复项/Solution.java
================================================
package 双指针遍历.q26_删除排序数组中的重复项;
/**
* 双指针 o(n)
*/
public class Solution {
public int removeDuplicates(int[] nums) {
if (nums.length < 2) {
return nums.length;
}
int c = 0;
for (int i = 1; i < nums.length; i++) {
if (nums[i] != nums[c]) {
c++;
nums[c] = nums[i];
}
}
return c + 1;
}
public static void main(String[] args) {
new Solution().removeDuplicates(new int[]{1, 1, 2});
}
}
================================================
FILE: src/双指针遍历/q3_无重复字符的最长子串/Solution.java
================================================
package 双指针遍历.q3_无重复字符的最长子串;
import java.util.HashMap;
/**
* Hash+双指针滑动窗口 o(n)
*/
public class Solution {
public int lengthOfLongestSubstring(String s) {
int left = 0;
int right = 0;
int len = 0;
HashMap map = new HashMap<>();
while (right < s.length()) {
Integer index = map.get(s.charAt(right));
map.put(s.charAt(right), right);
if (index != null && index >= left) {
left = index + 1;
}
if (right - left + 1 > len) {
len = right - left + 1;
}
right++;
}
return len;
}
}
================================================
FILE: src/双指针遍历/q42_接雨水/Solution.java
================================================
package 双指针遍历.q42_接雨水;
/**
* 暴力法o(n^2) 找出每个元素(柱子)上面的水量,可提前存储最大高度数组(两个左和右),最后遍历一次优化为o(n)
*/
public class Solution {
public int trap(int[] height) {
int ans = 0;
int size = height.length;
for (int i = 1; i < size - 1; i++) {
int maxLeft = 0, maxRight = 0;
for (int j = i; j >= 0; j--) {
maxLeft = Math.max(maxLeft, height[j]);
}
for (int j = i; j < size; j++) {
maxRight = Math.max(maxRight, height[j]);
}
ans += Math.min(maxLeft, maxRight) - height[i];
}
return ans;
}
public static void main(String[] args) {
new Solution().trap(new int[]{0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1});
}
}
================================================
FILE: src/回溯法/q10_正则表达式匹配/Solution.java
================================================
package 回溯法.q10_正则表达式匹配;
/**
* 回溯法 对于*字符,可以直接忽略模式串中这一部分,或者删除匹配串的第一个字符,前提是它能够匹配模式串当前位置字符,即 pattern[0]。如果两种操作中有任何一种使得剩下的字符串能匹配,那么初始时,匹配串和模式串就可以被匹配。
*/
public class Solution {
public boolean isMatch(String text, String pattern) {
if (pattern.isEmpty()){
return text.isEmpty();
}
boolean firstMatch = (!text.isEmpty() &&
(pattern.charAt(0) == text.charAt(0) || pattern.charAt(0) == '.'));
if (pattern.length() >= 2 && pattern.charAt(1) == '*') {
return (isMatch(text, pattern.substring(2)) ||
(firstMatch && isMatch(text.substring(1), pattern)));
} else {
return firstMatch && isMatch(text.substring(1), pattern.substring(1));
}
}
public static void main(String[] args) {
System.out.println(new Solution().isMatch("aaa", "a*a"));
}
}
================================================
FILE: src/回溯法/q22_括号生成/f1/Solution.java
================================================
package 回溯法.q22_括号生成.f1;
import java.util.*;
/**
* 暴力法 o(2^2n*n)
*/
public class Solution {
public boolean isValid(String s) {
Stack stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char t = s.charAt(i);
if (t == '(') {
stack.push(t);
} else {
if (stack.empty() || stack.pop() != '(') {
return false;
}
}
}
return stack.empty();
}
public List generateParenthesis(int n) {
List rs = new ArrayList<>();
if (n < 1) {
return rs;
}
String root = "(";
rs.add(root);
for (int k = 0; k < 2 * n - 1; k++) {
List tempList = new ArrayList<>();
for (int i = 0; i < rs.size(); i++) {
String temp = rs.get(i);
tempList.add(temp + "(");
tempList.add(temp + ")");
}
rs.clear();
rs.addAll(tempList);
}
rs.removeIf(s -> !isValid(s));
return rs;
}
public static void main(String[] args) {
new Solution().generateParenthesis(3);
}
}
================================================
FILE: src/回溯法/q22_括号生成/f2/Solution.java
================================================
package 回溯法.q22_括号生成.f2;
import java.util.ArrayList;
import java.util.List;
/**
* 回溯法 o((4^n)/(n^1/2))
*/
public class Solution {
public List generateParenthesis(int n) {
List ans = new ArrayList();
backtrack(ans, "", 0, 0, n);
return ans;
}
public void backtrack(List ans, String cur, int open, int close, int max) {
if (cur.length() == max * 2) {
ans.add(cur);
return;
}
if (open < max) {
backtrack(ans, cur + "(", open + 1, close, max);
}
if (close < open) {
backtrack(ans, cur + ")", open, close + 1, max);
}
}
public static void main(String[] args) {
System.out.println(new Solution().generateParenthesis(3));
}
}
================================================
FILE: src/回溯法/q40_组合总和2/Solution.java
================================================
package 回溯法.q40_组合总和2;
import java.util.*;
/**
* 回溯法 O(n*log(n))
*/
class Solution {
public List> combinationSum2(int[] candidates, int target) {
List> res = new ArrayList<>();
if (candidates.length == 0) {
return res;
}
Arrays.sort(candidates);
helper(candidates, target, 0, new LinkedList<>(), res);
return res;
}
public void helper(int[] candidates, int target, int start, LinkedList stack, List> res) {
if (start > candidates.length) {
return;
}
if (target == 0 && !stack.isEmpty()) {
List item = new ArrayList<>(stack);
res.add(item);
}
HashSet set = new HashSet<>();
for (int i = start; i < candidates.length; ++i) {
if (!set.contains(candidates[i]) && target >= candidates[i]) {
stack.push(candidates[i]);
helper(candidates, target - candidates[i], i + 1, stack, res);
stack.pop();
set.add(candidates[i]);
}
}
}
public static void main(String[] args) {
new Solution().combinationSum2(new int[]{10, 1, 2, 7, 6, 1, 5}, 8);
}
}
================================================
FILE: src/回溯法/q46_全排列/f1/Solution.java
================================================
package 回溯法.q46_全排列.f1;
import java.util.ArrayList;
import java.util.List;
/**
* 插队法 o((n-1)!+(n-2)!+···+2!+1!)
*/
public class Solution {
public List> fc(List> nums, int c) {
List> result = new ArrayList<>();
for (int i = 0; i < nums.size(); i++) {
for (int j = 0; j <= nums.get(i).size(); j++) {
List temp = new ArrayList<>(nums.get(i));
temp.add(j, c);
result.add(temp);
}
}
return result;
}
public List> permute(int[] nums) {
List> result = new ArrayList<>();
if (nums.length == 0) {
return result;
}
List to = new ArrayList<>();
to.add(nums[0]);
result.add(to);
for (int i = 1; i < nums.length; i++) {
result = fc(result, nums[i]);
}
System.out.println(result);
return result;
}
public static void main(String[] args) {
new Solution().permute(new int[]{1, 2, 3});
//4—>3!+2!+1!
}
}
================================================
FILE: src/回溯法/q46_全排列/f2/Solution.java
================================================
package 回溯法.q46_全排列.f2;
import java.util.ArrayList;
import java.util.List;
/**
* 回溯法(DFS深度优先遍历) o(n*n!)
*/
public class Solution {
public List> permute(int[] nums) {
int len = nums.length;
List> res = new ArrayList<>();
if (len == 0) {
return res;
}
boolean[] used = new boolean[len];
List path = new ArrayList<>();
dfs(nums, len, 0, path, used, res);
return res;
}
private void dfs(int[] nums, int len, int depth,
List path, boolean[] used,
List> res) {
if (depth == len) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; i++) {
if (!used[i]) {
path.add(nums[i]);
used[i] = true;
dfs(nums, len, depth + 1, path, used, res);
// 状态重置,是从深层结点回到浅层结点的过程,代码在形式上和递归之前是对称的
used[i] = false;
path.remove(depth);
}
}
}
public static void main(String[] args) {
int[] nums = {1, 2, 3};
Solution solution = new Solution();
List> lists = solution.permute(nums);
}
}
================================================
FILE: src/堆相关/q215_数组中的第K个最大元素/Solution.java
================================================
package 堆相关.q215_数组中的第K个最大元素;
import java.util.PriorityQueue;
/**
* 利用大根堆实现 o(n*log(k))
*/
public class Solution {
public int findKthLargest(int[] nums, int k) {
PriorityQueue heap =
new PriorityQueue<>((n1, n2) -> n1 - n2);
for (int n: nums) {
heap.add(n);
if (heap.size() > k){
heap.poll();
}
}
return heap.poll();
}
}
================================================
FILE: src/堆相关/q347_前K个高频元素/Solution.java
================================================
package 堆相关.q347_前K个高频元素;
import java.util.*;
/**
* 利用大根堆(PriorityQueue)实现 o(n*log(k))
*/
class Solution {
public List topKFrequent(int[] nums, int k) {
HashMap count = new HashMap<>();
for (int n : nums) {
count.put(n, count.getOrDefault(n, 0) + 1);
}
PriorityQueue heap = new PriorityQueue<>(Comparator.comparingInt(count::get));
for (int n : count.keySet()) {
heap.add(n);
if (heap.size() > k) {
heap.poll();
}
}
List topK = new LinkedList<>();
while (!heap.isEmpty()) {
topK.add(heap.poll());
}
Collections.reverse(topK);
return topK;
}
}
================================================
FILE: src/字典树/q648_单词替换/Solution.java
================================================
package 字典树.q648_单词替换;
import java.util.List;
/**
* 构建字典树(前缀树)o(n)
*/
class Solution {
public String replaceWords(List roots, String sentence) {
TrieNode trie = new TrieNode();
for (String root : roots) {
TrieNode cur = trie;
for (char letter : root.toCharArray()) {
if (cur.children[letter - 'a'] == null) {
cur.children[letter - 'a'] = new TrieNode();
}
cur = cur.children[letter - 'a'];
}
cur.word = root;
}
StringBuilder ans = new StringBuilder();
for (String word : sentence.split(" ")) {
if (ans.length() > 0) {
ans.append(" ");
}
TrieNode cur = trie;
for (char letter : word.toCharArray()) {
if (cur.children[letter - 'a'] == null || cur.word != null) {
break;
}
cur = cur.children[letter - 'a'];
}
ans.append(cur.word != null ? cur.word : word);
}
return ans.toString();
}
}
class TrieNode {
TrieNode[] children;
String word;
TrieNode() {
children = new TrieNode[26];
}
}
================================================
FILE: src/字符串操作/q14_最长公共前缀/Solution.java
================================================
package 字符串操作.q14_最长公共前缀;
/**
* 水平扫描 o(n)
*/
public class Solution {
public String longestCommonPrefix(String[] strs) {
if (strs.length == 0) {
return "";
}
if (strs.length == 1) {
return strs[0];
}
String pre = "";
int i = 0;
while (true) {
if (strs[0].length() == i) {
return pre;
}
char temp = strs[0].charAt(i);
for (int k = 1; k < strs.length; k++) {
if (strs[k].length() == i || temp != strs[k].charAt(i)) {
return pre;
}
}
pre += temp;
i++;
}
}
public static void main(String[] args) {
String[] s = new String[]{"c", "c"};
System.out.println(new Solution().longestCommonPrefix(s));
}
}
================================================
FILE: src/字符串操作/q6_Z字形变换/Solution.java
================================================
package 字符串操作.q6_Z字形变换;
import java.util.ArrayList;
import java.util.List;
/**
* o(n) 可用一boolean变量代替求余操作
*/
public class Solution {
public String convert(String s, int numRows) {
if (numRows == 1) {
return s;
}
int len = s.length();
int col = 0;
int n = 0;
List list = new ArrayList<>();
for (int i = 0; i < numRows; i++) {
StringBuffer temp = new StringBuffer();
list.add(temp);
}
while (n < len) {
int y = col % (numRows - 1);
if (y == 0) {
for (int i = 0; i < numRows && n < len; i++) {
list.get(i).append(s.charAt(n));
n++;
}
} else {
list.get(numRows - 1 - y).append(s.charAt(n));
n++;
}
col++;
}
String rs = "";
for (int i = 0; i < list.size(); i++) {
rs += list.get(i).toString();
}
return rs;
}
public static void main(String[] args) {
System.out.println(new Solution().convert("LEETCODEISHIRING", 4));
}
}
================================================
FILE: src/字符串操作/q763_划分字母区间/Solution.java
================================================
package 字符串操作.q763_划分字母区间;
import java.util.ArrayList;
import java.util.List;
/**
* 先存储每个字母最后出现的位置,最后遍历一次 o(n)
*/
public class Solution {
public List partitionLabels(String S) {
int[] last = new int[26];
for (int i = 0; i < S.length(); ++i) {
last[S.charAt(i) - 'a'] = i;
}
int j = 0, anchor = 0;
List ans = new ArrayList<>();
for (int i = 0; i < S.length(); ++i) {
j = Math.max(j, last[S.charAt(i) - 'a']);
if (i == j) {
ans.add(i - anchor + 1);
anchor = i + 1;
}
}
return ans;
}
public static void main(String[] args) {
new Solution().partitionLabels("abccaddbeffe");
}
}
================================================
FILE: src/快慢指针遍历/q141_环形链表/f1/ListNode.java
================================================
package 快慢指针遍历.q141_环形链表.f1;
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
================================================
FILE: src/快慢指针遍历/q141_环形链表/f1/Solution.java
================================================
package 快慢指针遍历.q141_环形链表.f1;
import java.util.HashSet;
import java.util.Set;
/**
* 哈希表 o(n)
*/
public class Solution {
public boolean hasCycle(ListNode head) {
Set nodesSeen = new HashSet<>();
while (head != null) {
if (nodesSeen.contains(head)) {
return true;
} else {
nodesSeen.add(head);
}
head = head.next;
}
return false;
}
}
================================================
FILE: src/快慢指针遍历/q141_环形链表/f2/ListNode.java
================================================
package 快慢指针遍历.q141_环形链表.f2;
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
================================================
FILE: src/快慢指针遍历/q141_环形链表/f2/Solution.java
================================================
package 快慢指针遍历.q141_环形链表.f2;
/**
* 快慢指针 o(n)
*/
public class Solution {
public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
}
================================================
FILE: src/快慢指针遍历/q202_快乐数/Solution.java
================================================
package 快慢指针遍历.q202_快乐数;
/**
* 快慢指针,思想同q141判断是否有环,用快慢指针找出循环终止条件 o(n)
*/
public class Solution {
private int bitSquareSum(int n) {
int sum = 0;
while (n > 0) {
int bit = n % 10;
sum += bit * bit;
n = n / 10;
}
return sum;
}
public boolean isHappy(int n) {
int slow = n;
int fast = n;
do {
slow = bitSquareSum(slow);
fast = bitSquareSum(fast);
fast = bitSquareSum(fast);
} while (slow != fast);
return slow == 1;
}
}
================================================
FILE: src/快慢指针遍历/q876_链表的中间结点/ListNode.java
================================================
package 快慢指针遍历.q876_链表的中间结点;
public class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
}
}
================================================
FILE: src/快慢指针遍历/q876_链表的中间结点/Solution.java
================================================
package 快慢指针遍历.q876_链表的中间结点;
/**
* 快慢指针法 o(n)
*/
public class Solution {
public ListNode middleNode(ListNode head) {
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
return slow;
}
}
================================================
FILE: src/数字操作/q172_阶乘后的零/f1/Solution.java
================================================
package 数字操作.q172_阶乘后的零.f1;
/**
* 找因子直接遍历(o(n)超时)
*/
public class Solution {
public int trailingZeroes(int num) {
int rs = 0;
for (int i = 1; i <= num; i++) {
int j = i;
while (j % 5 == 0) {
rs++;
j /= 5;
}
}
return rs;
}
}
================================================
FILE: src/数字操作/q172_阶乘后的零/f2/Solution.java
================================================
package 数字操作.q172_阶乘后的零.f2;
/**
* 基于方法一,寻找5出现的规律o(log(n))
*/
public class Solution {
public int trailingZeroes(int n) {
int count = 0;
while (n > 0) {
count += n / 5;
n = n / 5;
}
return count;
}
}
================================================
FILE: src/数字操作/q1920_基于排列构建数组/Solution.java
================================================
package 数字操作.q1920_基于排列构建数组;
/**
* 注意观察题目,数组中数字为[0,999]闭区间
*/
class Solution {
public int[] buildArray(int[] nums) {
int n = nums.length;
for (int i = 0; i < n; i++) {
nums[i] += 1000 * (nums[nums[i]] % 1000);
System.out.println(nums[i]);
}
for (int i = 0; i < n; i++) {
nums[i] /= 1000;
}
return nums;
}
public static void main(String[] args) {
int[] nums = new int[]{3, 2, 0, 1, 4};
new Solution().buildArray(nums);
}
}
================================================
FILE: src/数字操作/q258_各位相加/Solution.java
================================================
package 数字操作.q258_各位相加;
/**
* 找规律 o(1) xyz=100*x+10*y+z=99*x+9*y+x+y+z
*/
public class Solution {
public int addDigits(int num) {
if (num % 9 == 0 && num != 0) {
num = 9;
} else {
num %= 9;
}
return num;
}
}
================================================
FILE: src/数字操作/q43_字符串相乘/Solution.java
================================================
package 数字操作.q43_字符串相乘;
/**
* o(n) 可基于乘数某位与被乘数某位相乘产生结果的位置的规律优化
*/
class Solution {
public String multiply(String num1, String num2) {
if (num1.equals("0") || num2.equals("0")) {
return "0";
}
String res = "0";
for (int i = num2.length() - 1; i >= 0; i--) {
int carry = 0;
StringBuilder temp = new StringBuilder();
for (int j = 0; j < num2.length() - 1 - i; j++) {
temp.append(0);
}
int n2 = num2.charAt(i) - '0';
for (int j = num1.length() - 1; j >= 0 || carry != 0; j--) {
int n1 = j < 0 ? 0 : num1.charAt(j) - '0';
int product = (n1 * n2 + carry) % 10;
temp.append(product);
carry = (n1 * n2 + carry) / 10;
}
res = addStrings(res, temp.reverse().toString());
}
return res;
}
public String addStrings(String num1, String num2) {
StringBuilder builder = new StringBuilder();
int carry = 0;
for (int i = num1.length() - 1, j = num2.length() - 1;
i >= 0 || j >= 0 || carry != 0;
i--, j--) {
int x = i < 0 ? 0 : num1.charAt(i) - '0';
int y = j < 0 ? 0 : num2.charAt(j) - '0';
int sum = (x + y + carry) % 10;
builder.append(sum);
carry = (x + y + carry) / 10;
}
return builder.reverse().toString();
}
}
================================================
FILE: src/数字操作/q7_整数反转/f1/Solution.java
================================================
package 数字操作.q7_整数反转.f1;
/**
* 转成String o(n) 捕获异常判断是否溢出
*/
public class Solution {
public int reverse(int x) {
String s = String.valueOf(x);
String rs = "";
boolean f = false;
for (int i = s.length() - 1; i >= 0; i--) {
if (s.charAt(i) == '-') {
f = true;
} else {
rs += s.charAt(i);
}
}
try {
return f ? Integer.parseInt(rs) * (-1) : Integer.parseInt(rs);
} catch (Exception e) {
return 0;
}
}
public static void main(String[] args) {
System.out.println(new Solution().reverse(1234));
}
}
================================================
FILE: src/数字操作/q7_整数反转/f2/Solution.java
================================================
package 数字操作.q7_整数反转.f2;
/**
* 求余(判断是否溢出有多种方式) o(log(n))
*/
public class Solution {
public int reverse(int x) {
int rs = 0;
while (true) {
int y = x % 10;
x = x / 10;
if (rs * 10 / 10 != rs) {
return 0;
}
rs = rs * 10 + y;
if (x == 0) {
break;
}
}
return rs;
}
}
================================================
FILE: src/数字操作/q8_字符串转换整数/Solution.java
================================================
package 数字操作.q8_字符串转换整数;
/**
* o(n) 重点还是判断溢出
*/
public class Solution {
public int myAtoi(String str) {
str = str.trim();
if (str.length() < 1) {
return 0;
}
boolean negative = false;
if (str.charAt(0) == '-') {
negative = true;
str = str.substring(1);
} else if (str.charAt(0) == '+') {
str = str.substring(1);
}
int rs = 0;
for (int i = 0; i < str.length(); i++) {
char t = str.charAt(i);
if (Character.isDigit(t)) {
int temp = rs * 10 - '0' + t;
if ((temp - t + '0') / 10 != rs || temp < 0) {
return negative ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
rs = temp;
} else {
break;
}
}
return negative ? -rs : rs;
}
public static void main(String[] args) {
System.out.println(new Solution().myAtoi("2147483648"));
}
}
================================================
FILE: src/数字操作/q9_回文数/Solution.java
================================================
package 数字操作.q9_回文数;
/**
* 不转换成String 反转一半的数字o(log(n))
*/
public class Solution {
public boolean isPalindrome(int x) {
if (x < 0) {
return false;
}
if (x < 10) {
return true;
}
if (x % 10 == 0) {
return false;
}
int rs = 0;
while (rs < x / 10) {
int y = x % 10;
x = x / 10;
rs = rs * 10 + y;
if (rs == x) {
return true;
} else if (x / 10 == rs) {
return true;
}
}
return false;
}
}
================================================
FILE: src/数组操作/q384_打乱数组/Solution.java
================================================
package 数组操作.q384_打乱数组;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* 洗牌算法 o(n)
*/
public class Solution {
private int[] array;
private int[] original;
private Random rand = new Random();
private List getArrayCopy() {
List asList = new ArrayList<>();
for (int i = 0; i < array.length; i++) {
asList.add(array[i]);
}
return asList;
}
public Solution(int[] nums) {
array = nums;
original = nums.clone();
}
public int[] reset() {
array = original;
original = original.clone();
return array;
}
public int[] shuffle() {
List aux = getArrayCopy();
for (int i = 0; i < array.length; i++) {
int removeIdx = rand.nextInt(aux.size());
array[i] = aux.get(removeIdx);
aux.remove(removeIdx);
}
return array;
}
}
================================================
FILE: src/数组操作/q54_螺旋矩阵/Solution.java
================================================
package 数组操作.q54_螺旋矩阵;
import java.util.ArrayList;
import java.util.List;
/**
* 方向变量模拟路径 o(n)
*/
public class Solution {
public List spiralOrder(int[][] matrix) {
List rs = new ArrayList<>();
if (matrix.length == 0 || matrix[0].length == 0) {
return rs;
}
int m = matrix.length;
int n = matrix[0].length;
boolean[][] visited = new boolean[m][n];
int i = 0;
int j = 0;
int direction = 1;
while (true) {
if (i < 0 || j < 0 || i == m || j == n || visited[i][j]) {
break;
}
rs.add(matrix[i][j]);
visited[i][j] = true;
switch (direction) {
case 1:
if (j + 1 == n || visited[i][j + 1]) {
i++;
direction = 2;
} else {
j++;
}
break;
case 2:
if (i + 1 == m || visited[i + 1][j]) {
j--;
direction = 3;
} else {
i++;
}
break;
case 3:
if (j == 0 || visited[i][j - 1]) {
i--;
direction = 4;
} else {
j--;
}
break;
case 4:
if (visited[i - 1][j]) {
j++;
direction = 1;
} else {
i--;
}
break;
default:
break;
}
}
return rs;
}
public static void main(String[] args) {
System.out.println(new Solution().spiralOrder(new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}));
}
}
================================================
FILE: src/数组操作/q581_最短无序连续子数组/Solution.java
================================================
package 数组操作.q581_最短无序连续子数组;
import java.util.Arrays;
/**
* 利用排序 o(n*log(n))
*/
public class Solution {
public int findUnsortedSubarray(int[] nums) {
if (nums == null || nums.length < 1) {
return 0;
}
int[] cloneNums = nums.clone();
Arrays.sort(nums);
int begin = Integer.MAX_VALUE;
int end = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != cloneNums[i]) {
begin = Math.min(begin, i);
end = Math.max(end, i);
}
}
return Math.max(end - begin + 1, 0);
}
public static void main(String[] args) {
new Solution().findUnsortedSubarray(new int[]{2, 6, 4, 8, 10, 9, 15});
}
}
================================================
FILE: src/数组操作/q73_矩阵置零/Solution.java
================================================
package 数组操作.q73_矩阵置零;
/**
* 用每行和每列的第一个元素作为标记,空间复杂度是o(1),时间复杂度 o(m*n)
*/
public class Solution {
public void setZeroes(int[][] matrix) {
//第一行是否需要置零
boolean row = false;
//第一列是否需要置零
boolean column = false;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == 0) {
if (i == 0) {
row = true;
}
if (j == 0) {
column = true;
}
//第i行第一个元素置零,表示这一行需要全部置零
matrix[i][0] = 0;
//第j列第一个元素置零,表示这一列需要全部置零
matrix[0][j] = 0;
}
}
}
for (int i = 1; i < matrix.length; i++) {
if (matrix[i][0] == 0) {
for (int j = 1; j < matrix[i].length; j++) {
matrix[i][j] = 0;
}
}
}
for (int j = 1; j < matrix[0].length; j++) {
if (matrix[0][j] == 0) {
for (int i = 1; i < matrix.length; i++) {
matrix[i][j] = 0;
}
}
}
if (row) {
for (int j = 1; j < matrix[0].length; j++) {
matrix[0][j] = 0;
}
}
if (column) {
for (int i = 1; i < matrix.length; i++) {
matrix[i][0] = 0;
}
}
}
}
================================================
FILE: src/数组操作/q78_子集/Solution.java
================================================
package 数组操作.q78_子集;
import java.util.ArrayList;
import java.util.List;
/**
* 向子集中添加子集合 o(n*2^n)
*/
public class Solution {
public List> subsets(int[] nums) {
List> result = new ArrayList<>();
result.add(new ArrayList<>());
for (int i = 0; i < nums.length; i++) {
int size = result.size();
for (int j = 0; j < size; j++) {
List temp = new ArrayList<>(result.get(j));
temp.add(nums[i]);
result.add(temp);
}
}
return result;
}
}
================================================
FILE: src/数组操作/q945_使数组唯一的最小增量/Solution.java
================================================
package 数组操作.q945_使数组唯一的最小增量;
import java.util.Arrays;
/**
* 先排序再遍历一次 o(n*log(n))
*/
public class Solution {
public int minIncrementForUnique(int[] A) {
if (A == null || A.length == 0 || A.length == 1) {
return 0;
}
int rs = 0;
Arrays.sort(A);
int t = A[0];
for (int i = 1; i < A.length; i++) {
if (A[i] <= t) {
rs = rs + t - A[i] + 1;
A[i] = t + 1;
}
t = A[i];
}
return rs;
}
}
================================================
FILE: src/栈相关/q155_最小栈/MinStack.java
================================================
package 栈相关.q155_最小栈;
import java.util.Stack;
/**
* 不使用辅助栈,每次push两个元素
*/
public class MinStack {
private Stack stack;
public MinStack() {
stack = new Stack<>();
}
public void push(int x) {
if (stack.isEmpty()) {
stack.push(x);
stack.push(x);
} else {
int tmp = stack.peek();
stack.push(x);
if (tmp < x) {
stack.push(tmp);
} else {
stack.push(x);
}
}
}
public void pop() {
stack.pop();
stack.pop();
}
public int top() {
return stack.get(stack.size() - 2);
}
public int getMin() {
return stack.peek();
}
}
================================================
FILE: src/栈相关/q20_有效的括号/Solution.java
================================================
package 栈相关.q20_有效的括号;
import java.util.Stack;
/**
* 利用栈 o(n)
*/
public class Solution {
public boolean isValid(String s) {
Stack stack = new Stack<>();
for (int i = 0; i < s.length(); i++) {
char t = s.charAt(i);
if (t == '(' || t == '[' || t == '{') {
stack.push(t);
} else {
if (stack.empty()) {
return false;
}
if (t == ')') {
if (stack.pop() != '(') {
return false;
}
} else if (t == ']') {
if (stack.pop() != '[') {
return false;
}
} else {
if (stack.pop() != '{') {
return false;
}
}
}
}
return stack.empty();
}
public static void main(String[] args) {
System.out.println(new Solution().isValid("()"));
}
}
================================================
FILE: src/栈相关/q224_基本计算器/f1/Solution.java
================================================
package 栈相关.q224_基本计算器.f1;
import java.util.Stack;
/**
* 双栈(操作数栈+操作符栈)o(n)
*/
public class Solution {
public int calculate(String s) {
char[] array = s.toCharArray();
int n = array.length;
Stack num = new Stack<>();
Stack op = new Stack<>();
int temp = -1;
for (int i = 0; i < n; i++) {
if (array[i] == ' ') {
continue;
}
// 数字进行累加
if (isNumber(array[i])) {
if (temp == -1) {
temp = array[i] - '0';
} else {
temp = temp * 10 + array[i] - '0';
}
} else {
//将数字入栈
if (temp != -1) {
num.push(temp);
temp = -1;
}
//遇到操作符
if (isOperation(array[i] + "")) {
while (!op.isEmpty()) {
if (op.peek() == '(') {
break;
}
//不停的出栈,进行运算,并将结果再次压入栈中
int num1 = num.pop();
int num2 = num.pop();
if (op.pop() == '+') {
num.push(num1 + num2);
} else {
num.push(num2 - num1);
}
}
//当前运算符入栈
op.push(array[i]);
} else {
//遇到左括号,直接入栈
if (array[i] == '(') {
op.push(array[i]);
}
//遇到右括号,不停的进行运算,直到遇到左括号
if (array[i] == ')') {
while (op.peek() != '(') {
int num1 = num.pop();
int num2 = num.pop();
if (op.pop() == '+') {
num.push(num1 + num2);
} else {
num.push(num2 - num1);
}
}
op.pop();
}
}
}
}
if (temp != -1) {
num.push(temp);
}
//将栈中的其他元素继续运算
while (!op.isEmpty()) {
int num1 = num.pop();
int num2 = num.pop();
if (op.pop() == '+') {
num.push(num1 + num2);
} else {
num.push(num2 - num1);
}
}
return num.pop();
}
private boolean isNumber(char c) {
return c >= '0' && c <= '9';
}
private boolean isOperation(String t) {
return t.equals("+") || t.equals("-") || t.equals("*") || t.equals("/");
}
}
================================================
FILE: src/栈相关/q224_基本计算器/f2/Solution.java
================================================
package 栈相关.q224_基本计算器.f2;
import java.util.Stack;
/**
* 单栈 拆分递归思想 o(n)
*/
public class Solution {
public int evaluateExpr(Stack