0%

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.demo.s79;

/**
* 单词搜索
* 给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false 。
*
* 单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/word-search
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public boolean exist(char[][] board, String word) {
int h = board.length, w = board[0].length;
boolean[][] visited = new boolean[h][w];
//遍历二维数组
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
//检查单词是否存在
boolean flag = check(board, visited, i, j, word, 0);
if (flag) {
return true;
}
}
}
return false;
}

public boolean check(char[][] board, boolean[][] visited, int i, int j, String s, int k) {
//对比字符,到达字符长度,递归结束条件
if (board[i][j] != s.charAt(k)) {
return false;
} else if (k == s.length() - 1) {
return true;
}
//标记为已访问过
visited[i][j] = true;
//上下左右四个方向查找
int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
boolean result = false;
for (int[] dir : directions) {
int newi = i + dir[0], newj = j + dir[1];
//边界判断
if (newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length) {
//没有访问过的网格,继续递归查找
if (!visited[newi][newj]) {
boolean flag = check(board, visited, newi, newj, s, k + 1);
if (flag) {
result = true;
break;
}
}
}
}
//没找到则标记为没有访问过,下次有可能组成新的单词时,再次访问
visited[i][j] = false;
return result;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.demo.s78;

import java.util.ArrayList;
import java.util.List;

/**
* 子集
* 给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。
*
* 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。
*/
public class Solution {
List<Integer> t = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();

public List<List<Integer>> subsets(int[] nums) {
int n = nums.length;
for (int mask = 0; mask < (1 << n); ++mask) {
t.clear();
for (int i = 0; i < n; ++i) {
if ((mask & (1 << i)) != 0) {
t.add(nums[i]);
}
}
ans.add(new ArrayList<Integer>(t));
}
return ans;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.demo.s77;

import java.util.ArrayList;
import java.util.List;

/**
* 组合
* 给定两个整数 n 和 k,返回范围 [1, n] 中所有可能的 k 个数的组合。
*
* 你可以按 任何顺序 返回答案。
*/
public class Solution {
List<Integer> temp = new ArrayList<Integer>();
List<List<Integer>> ans = new ArrayList<List<Integer>>();

public List<List<Integer>> combine(int n, int k) {
dfs(1, n, k);
return ans;
}

public void dfs(int cur, int n, int k) {
// 剪枝:temp 长度加上区间 [cur, n] 的长度小于 k,不可能构造出长度为 k 的 temp
if (temp.size() + (n - cur + 1) < k) {
return;
}
// 记录合法的答案
if (temp.size() == k) {
ans.add(new ArrayList<Integer>(temp));
return;
}
// 考虑选择当前位置
temp.add(cur);
dfs(cur + 1, n, k);
temp.remove(temp.size() - 1);
// 考虑不选择当前位置
dfs(cur + 1, n, k);
}

}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package com.demo.s76;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
* 最小覆盖子串
* 给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。
*
*  
*
* 注意:
*
* 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
* 如果 s 中存在这样的子串,我们保证它是唯一的答案。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/minimum-window-substring
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
//t 中每个字符出现的次数 存到 ori中
Map<Character, Integer> ori = new HashMap<Character, Integer>();
//记录字符串 s 子串中字符出现次数
Map<Character, Integer> cnt = new HashMap<Character, Integer>();

public String minWindow(String s, String t) {
int tLen = t.length();
//遍历t 统计出 ori
for (int i = 0; i < tLen; i++) {
char c = t.charAt(i);
ori.put(c, ori.getOrDefault(c, 0) + 1);
}
int l = 0, r = -1;
//子字符串长度len
int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
int sLen = s.length();
//子字符串从 0 开始 到 r
while (r < sLen) {
++r;
//如果 s字符串的字符出现了 t总字符
if (r < sLen && ori.containsKey(s.charAt(r))) {
//则累加值 放到cnt中计数
cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
}
//如果满足要求了,尝试缩短子串
while (check() && l <= r) {
//如果比当前最小长度len 还小 则 更新len
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
ansR = l + len;
}
// l 左移 对应统计cnt中字符数字也要减1
if (ori.containsKey(s.charAt(l))) {
cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
}
++l;
}
}
//如果ansL 存在 则返回 子字符串
return ansL == -1 ? "" : s.substring(ansL, ansR);
}

public boolean check() {
//检查是否完全满足 t的字符及出现次数要求
Iterator iter = ori.entrySet().iterator();
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
Character key = (Character) entry.getKey();
Integer val = (Integer) entry.getValue();
if (cnt.getOrDefault(key, 0) < val) {
return false;
}
}
return true;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
package com.demo.s75;

/**
* <p>给定一个包含红色、白色和蓝色、共&nbsp;<code>n</code><em> </em>个元素的数组<meta charset="UTF-8" />&nbsp;<code>nums</code>&nbsp;,<strong><a href="https://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95" target="_blank">原地</a></strong>对它们进行排序,使得相同颜色的元素相邻,并按照红色、白色、蓝色顺序排列。</p>
*
* <p>我们使用整数 <code>0</code>、&nbsp;<code>1</code> 和 <code>2</code> 分别表示红色、白色和蓝色。</p>
*/
public class Solution {
public void sortColors(int[] nums) {
int n = nums.length;
int ptr = 0;
for (int i = 0; i < n; ++i) {
if (nums[i] == 0) {
int temp = nums[i];
nums[i] = nums[ptr];
nums[ptr] = temp;
++ptr;
}
}
for (int i = ptr; i < n; ++i) {
if (nums[i] == 1) {
int temp = nums[i];
nums[i] = nums[ptr];
nums[ptr] = temp;
++ptr;
}
}
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package com.demo.s74;

/**
* <p>编写一个高效的算法来判断 <code>m x n</code> 矩阵中,是否存在一个目标值。该矩阵具有如下特性:</p>
*
* <ul>
* <li>每行中的整数从左到右按升序排列。</li>
* <li>每行的第一个整数大于前一行的最后一个整数。</li>
* </ul>
*
*/
public class Solution {

public boolean searchMatrix(int[][] matrix, int target) {
int rowIndex = binarySearchFirstColumn(matrix, target);
if (rowIndex < 0) {
return false;
}
return binarySearchRow(matrix[rowIndex], target);
}

public int binarySearchFirstColumn(int[][] matrix, int target) {
int low = -1, high = matrix.length - 1;
while (low < high) {
int mid = (high - low + 1) / 2 + low;
if (matrix[mid][0] <= target) {
low = mid;
} else {
high = mid - 1;
}
}
return low;
}

public boolean binarySearchRow(int[] row, int target) {
int low = 0, high = row.length - 1;
while (low <= high) {
int mid = (high - low) / 2 + low;
if (row[mid] == target) {
return true;
} else if (row[mid] > target) {
high = mid - 1;
} else {
low = mid + 1;
}
}
return false;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.demo.s73;

/**
* 矩阵置零
* <p>给定一个&nbsp;<code><em>m</em> x <em>n</em></code> 的矩阵,如果一个元素为 <strong>0 </strong>,则将其所在行和列的所有元素都设为 <strong>0</strong> 。请使用 <strong><a href="http://baike.baidu.com/item/%E5%8E%9F%E5%9C%B0%E7%AE%97%E6%B3%95" target="_blank">原地</a></strong> 算法<strong>。</strong></p>
*/
public class Solution {
public void setZeroes(int[][] matrix) {
int m = matrix.length, n = matrix[0].length;
boolean[] row = new boolean[m];
boolean[] col = new boolean[n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (matrix[i][j] == 0) {
row[i] = col[j] = true;
}
}
}
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (row[i] || col[j]) {
matrix[i][j] = 0;
}
}
}
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.demo.s72;

/**
* 编辑距离
*/
public class Solution {
public int minDistance(String word1, String word2) {
int m = word1.length();
int n = word2.length();

if(m == 0 || n == 0) {
return m + n;
}
int[][] dp = new int[m + 1][n + 1];
//j == 0 也就是 words2 长度为0时,编辑距离 完全取决于words1长度
for(int i = 0; i< m + 1; i++) {
dp[i][0] = i;
}
//i == 0 也就是 words1 长度为0时,编辑距离 完全取决于words2长度
for(int j = 0; j< n + 1; j++) {
dp[0][j] = j;
}

for(int i = 1; i<= m; i++) {
for(int j = 1; j<= n; j++) {
//字符相等 则编辑距离不变
if(word1.charAt(i-1) == word2.charAt(j-1)) {
dp[i][j] = dp[i-1][j-1];
} else {
//取决于前者编辑距离的最小值 + 1
dp[i][j] = Math.min(dp[i-1][j], Math.min(dp[i][j-1], dp[i-1][j-1])) + 1;
}
}
}
return dp[m][n];
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
package com.demo.s718;


/**
*给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子数组的长度 。
*/
public class Solution {
public int findLength(int[] A, int[] B) {
return A.length < B.length ? findMax(A, B) : findMax(B, A);
}

int findMax(int[] A, int[] B) {
int max = 0;
int an = A.length, bn = B.length;
for(int len=1; len <= an; len++) {
max = Math.max(max, maxLen(A, 0, B, bn - len, len));
}
for(int j=bn-an; j >= 0;j--) {
max = Math.max(max, maxLen(A, 0, B, j, an));
}
for(int i=1;i<an;i++) {
max = Math.max(max, maxLen(A, i, B, 0, an - i));
}
return max;
}

int maxLen(int[] a, int i, int[] b, int j, int len) {
int count = 0, max = 0;
for(int k = 0; k < len; k++) {
if(a[i+k] == b[j+k]) {
count++;
} else if(count > 0) {
max = Math.max(max, count);
count = 0;
}
}
return count > 0 ? Math.max(max, count) : max;
}
}

代码解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.demo.s71;

import java.util.Deque;
import java.util.LinkedList;

/**
* 简化路径
* 给你一个字符串 path ,表示指向某一文件或目录的 Unix 风格 绝对路径 (以 '/' 开头),请你将其转化为更加简洁的规范路径。
*
* 在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。任意多个连续的斜杠(即,'//')都被视为单个斜杠 '/' 。 对于此问题,任何其他格式的点(例如,'...')均被视为文件/目录名称。
*
* 请注意,返回的 规范路径 必须遵循下述格式:
*
* 始终以斜杠 '/' 开头。
* 两个目录名之间必须只有一个斜杠 '/' 。
* 最后一个目录名(如果存在)不能 以 '/' 结尾。
* 此外,路径仅包含从根目录到目标文件或目录的路径上的目录(即,不含 '.' 或 '..')。
* 返回简化后得到的 规范路径 。
*
* 来源:力扣(LeetCode)
* 链接:https://leetcode.cn/problems/simplify-path
* 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
*/
public class Solution {
public String simplifyPath(String path) {
// 双端队列
Deque<String> queue = new LinkedList<>();
// 分割字符
String[] res = path.split("/");
for(int i = 0; i < res.length; i++){
String s = res[i];
if(s.equals(".") || s.equals("")) continue;
else if (s.equals("..")){
if(!queue.isEmpty()){
queue.pollLast();
}
}else{
queue.offer(s);
}
}
// 拼接
StringBuilder sb = new StringBuilder("/");
while(!queue.isEmpty()){
sb.append(queue.poll());
if(!queue.isEmpty()){
sb.append("/");
}
}
// 判空
return sb.toString().equals("") ? "/" : sb.toString();
}
}