Skip to content

Commit 26444d6

Browse files
committed
auto commit
1 parent e3815ad commit 26444d6

File tree

1 file changed

+106
-90
lines changed

1 file changed

+106
-90
lines changed

notes/Leetcode 题解.md

Lines changed: 106 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ A partition like "ababcbacadefegde", "hijhklij" is incorrect, because it splits
489489

490490
```java
491491
public List<Integer> partitionLabels(String S) {
492-
List<Integer> ret = new ArrayList<>();
492+
List<Integer> partitions = new ArrayList<>();
493493
int[] lastIndexs = new int[26];
494494
for (int i = 0; i < S.length(); i++) {
495495
lastIndexs[S.charAt(i) - 'a'] = i;
@@ -502,10 +502,10 @@ public List<Integer> partitionLabels(String S) {
502502
if (index == i) continue;
503503
if (index > lastIndex) lastIndex = index;
504504
}
505-
ret.add(lastIndex - firstIndex + 1);
505+
partitions.add(lastIndex - firstIndex + 1);
506506
firstIndex = lastIndex + 1;
507507
}
508-
return ret;
508+
return partitions;
509509
}
510510
```
511511

@@ -564,9 +564,9 @@ Input: numbers={2, 7, 11, 15}, target=9
564564
Output: index1=1, index2=2
565565
```
566566

567-
题目描述:从一个已经排序的数组中找出两个数,使它们的和为 0。
567+
题目描述:在有序数组中找出两个数,使它们的和为 0。
568568

569-
使用双指针,一个指针指向元素较小的值,一个指针指向元素较大的值。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
569+
使用双指针,一个指针指向值较小的元素,一个指针指向值较大的元素。指向较小元素的指针从头向尾遍历,指向较大元素的指针从尾向头遍历。
570570

571571
如果两个指针指向元素的和 sum == target,那么得到要求的结果;如果 sum > target,移动较大的元素,使 sum 变小一些;如果 sum < target,移动较小的元素,使 sum 变大一些。
572572

@@ -583,6 +583,31 @@ public int[] twoSum(int[] numbers, int target) {
583583
}
584584
```
585585

586+
**两数平方和**
587+
588+
[Leetcode : 633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/)
589+
590+
```html
591+
Input: 5
592+
Output: True
593+
Explanation: 1 * 1 + 2 * 2 = 5
594+
```
595+
596+
题目描述:判断一个数是否为两个数的平方和,例如 5 = 1<sup>2</sup> + 2<sup>2</sup>。
597+
598+
```java
599+
public boolean judgeSquareSum(int c) {
600+
int i = 0, j = (int) Math.sqrt(c);
601+
while (i <= j) {
602+
int powSum = i * i + j * j;
603+
if (powSum == c) return true;
604+
if (powSum > c) j--;
605+
else i++;
606+
}
607+
return false;
608+
}
609+
```
610+
586611
**反转字符串中的元音字符**
587612

588613
[Leetcode : 345. Reverse Vowels of a String (Easy)](https://leetcode.com/problems/reverse-vowels-of-a-string/description/)
@@ -597,54 +622,24 @@ Given s = "leetcode", return "leotcede".
597622
private HashSet<Character> vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
598623

599624
public String reverseVowels(String s) {
600-
if (s.length() == 0) return s;
601625
int i = 0, j = s.length() - 1;
602626
char[] result = new char[s.length()];
603627
while (i <= j) {
604628
char ci = s.charAt(i);
605629
char cj = s.charAt(j);
606630
if (!vowels.contains(ci)) {
607-
result[i] = ci;
608-
i++;
631+
result[i++] = ci;
609632
} else if (!vowels.contains(cj)) {
610-
result[j] = cj;
611-
j--;
633+
result[j--] = cj;
612634
} else {
613-
result[i] = cj;
614-
result[j] = ci;
615-
i++;
616-
j--;
635+
result[i++] = cj;
636+
result[j--] = ci;
617637
}
618638
}
619639
return new String(result);
620640
}
621641
```
622642

623-
**两数平方和**
624-
625-
[Leetcode : 633. Sum of Square Numbers (Easy)](https://leetcode.com/problems/sum-of-square-numbers/description/)
626-
627-
```html
628-
Input: 5
629-
Output: True
630-
Explanation: 1 * 1 + 2 * 2 = 5
631-
```
632-
633-
题目描述:判断一个数是否为两个数的平方和,例如 5 = 1<sup>2</sup> + 2<sup>2</sup>。
634-
635-
```java
636-
public boolean judgeSquareSum(int c) {
637-
int i = 0, j = (int) Math.sqrt(c);
638-
while (i <= j) {
639-
int powSum = i * i + j * j;
640-
if (powSum == c) return true;
641-
if (powSum > c) j--;
642-
else i++;
643-
}
644-
return false;
645-
}
646-
```
647-
648643
**回文字符串**
649644

650645
[Leetcode : 680. Valid Palindrome II (Easy)](https://leetcode.com/problems/valid-palindrome-ii/description/)
@@ -659,20 +654,20 @@ Explanation: You could delete the character 'c'.
659654

660655
```java
661656
public boolean validPalindrome(String s) {
662-
int i = 0, j = s.length() - 1;
663-
while (i < j) {
657+
int i = -1, j = s.length();
658+
while (++i < --j) {
664659
if (s.charAt(i) != s.charAt(j)) {
665660
return isPalindrome(s, i, j - 1) || isPalindrome(s, i + 1, j);
666661
}
667-
i++;
668-
j--;
669662
}
670663
return true;
671664
}
672665

673-
private boolean isPalindrome(String s, int l, int r) {
674-
while (l < r) {
675-
if (s.charAt(l++) != s.charAt(r--)) return false;
666+
private boolean isPalindrome(String s, int i, int j) {
667+
while (i < j) {
668+
if (s.charAt(i++) != s.charAt(j--)) {
669+
return false;
670+
}
676671
}
677672
return true;
678673
}
@@ -682,6 +677,14 @@ private boolean isPalindrome(String s, int l, int r) {
682677

683678
[Leetcode : 88. Merge Sorted Array (Easy)](https://leetcode.com/problems/merge-sorted-array/description/)
684679

680+
```html
681+
Input:
682+
nums1 = [1,2,3,0,0,0], m = 3
683+
nums2 = [2,5,6], n = 3
684+
685+
Output: [1,2,2,3,5,6]
686+
```
687+
685688
题目描述:把归并结果存到第一个数组上。
686689

687690
```java
@@ -708,10 +711,9 @@ public void merge(int[] nums1, int m, int[] nums2, int n) {
708711
public boolean hasCycle(ListNode head) {
709712
if (head == null) return false;
710713
ListNode l1 = head, l2 = head.next;
711-
while (l1 != null && l2 != null) {
714+
while (l1 != null && l2 != null && l2.next != null) {
712715
if (l1 == l2) return true;
713716
l1 = l1.next;
714-
if (l2.next == null) break;
715717
l2 = l2.next.next;
716718
}
717719
return false;
@@ -734,18 +736,28 @@ Output:
734736

735737
```java
736738
public String findLongestWord(String s, List<String> d) {
737-
String ret = "";
738-
for (String str : d) {
739-
for (int i = 0, j = 0; i < s.length() && j < str.length(); i++) {
740-
if (s.charAt(i) == str.charAt(j)) j++;
741-
if (j == str.length()) {
742-
if (ret.length() < str.length() || (ret.length() == str.length() && ret.compareTo(str) > 0)) {
743-
ret = str;
744-
}
745-
}
739+
String longestWord = "";
740+
for (String target : d) {
741+
int l1 = longestWord.length(), l2 = target.length();
742+
if (l1 > l2 || (l1 == l2 && longestWord.compareTo(target) < 0)) {
743+
continue;
744+
}
745+
if (isValid(s, target)) {
746+
longestWord = target;
746747
}
747748
}
748-
return ret;
749+
return longestWord;
750+
}
751+
752+
private boolean isValid(String s, String target) {
753+
int i = 0, j = 0;
754+
while (i < s.length() && j < target.length()) {
755+
if (s.charAt(i) == target.charAt(j)) {
756+
j++;
757+
}
758+
i++;
759+
}
760+
return j == target.length();
749761
}
750762
```
751763

@@ -913,7 +925,7 @@ public String frequencySort(String s) {
913925

914926
<div align="center"> <img src="../pics//4ff355cf-9a7f-4468-af43-e5b02038facc.jpg"/> </div><br>
915927

916-
广度优先搜索的搜索过程有点像一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个长度。需要注意的是,遍历过的节点不能再次被遍历。
928+
广度优先搜索的搜索过程有点像一层一层地进行遍历,每层遍历都以上一层遍历的结果作为起点,遍历一个距离能访问到的所有节点。需要注意的是,遍历过的节点不能再次被遍历。
917929

918930
第一层:
919931

@@ -931,11 +943,11 @@ public String frequencySort(String s) {
931943
- 4 -> {}
932944
- 3 -> {}
933945

934-
可以看到,每一轮遍历的节点都与根节点路径长度相同。设 d<sub>i</sub> 表示第 i 个节点与根节点的路径长度,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 d<sub>i</sub><=d<sub>j</sub>。利用这个结论,可以求解最短路径等 **最优解** 问题:第一次遍历到目的节点,其所经过的路径为最短路径。
946+
可以看到,每一轮遍历的节点都与根节点距离相同。设 d<sub>i</sub> 表示第 i 个节点与根节点的距离,推导出一个结论:对于先遍历的节点 i 与后遍历的节点 j,有 d<sub>i</sub><=d<sub>j</sub>。利用这个结论,可以求解最短路径等 **最优解** 问题:第一次遍历到目的节点,其所经过的路径为最短路径。
935947

936948
在程序实现 BFS 时需要考虑以下问题:
937949

938-
- 队列:用来存储每一轮遍历的节点
950+
- 队列:用来存储每一轮遍历得到的节点
939951
- 标记:对于遍历过的节点,应该将它标记,防止重复遍历。
940952

941953
**计算在网格中从原点到特定点的最短路径长度**
@@ -947,34 +959,38 @@ public String frequencySort(String s) {
947959
[1,0,1,1]]
948960
```
949961

950-
1 表示可以经过某个位置。
962+
题目描述:1 表示可以经过某个位置,求解从 (0, 0) 位置到 (tr, tc) 位置的最短路径长度
951963

952964
```java
953965
public int minPathLength(int[][] grids, int tr, int tc) {
954-
int[][] next = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
966+
int[][] direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
955967
int m = grids.length, n = grids[0].length;
956968
Queue<Position> queue = new LinkedList<>();
957-
queue.add(new Position(0, 0, 1));
969+
queue.add(new Position(0, 0));
970+
int pathLength = 0;
958971
while (!queue.isEmpty()) {
959-
Position pos = queue.poll();
960-
for (int i = 0; i < 4; i++) {
961-
Position nextPos = new Position(pos.r + next[i][0], pos.c + next[i][1], pos.length + 1);
962-
if (nextPos.r < 0 || nextPos.r >= m || nextPos.c < 0 || nextPos.c >= n) continue;
963-
if (grids[nextPos.r][nextPos.c] != 1) continue;
964-
grids[nextPos.r][nextPos.c] = 0; // 标记已经访问过
965-
if (nextPos.r == tr && nextPos.c == tc) return nextPos.length;
966-
queue.add(nextPos);
972+
int size = queue.size();
973+
pathLength++;
974+
while (size-- > 0) {
975+
Position cur = queue.poll();
976+
for (int[] d : direction) {
977+
Position next = new Position(cur.r + d[0], cur.c + d[1]);
978+
if (next.r < 0 || next.r >= m || next.c < 0 || next.c >= n) continue;
979+
grids[next.r][next.c] = 0;
980+
if (next.r == tr && next.c == tc) return pathLength;
981+
queue.add(next);
982+
}
967983
}
968984
}
969985
return -1;
970986
}
971987

972988
private class Position {
973-
int r, c, length;
974-
Position(int r, int c, int length) {
989+
int r, c;
990+
991+
Position(int r, int c) {
975992
this.r = r;
976993
this.c = c;
977-
this.length = length;
978994
}
979995
}
980996
```
@@ -1082,8 +1098,8 @@ private void dfs(char[][] grid, int i, int j) {
10821098
return;
10831099
}
10841100
grid[i][j] = '0';
1085-
for (int k = 0; k < direction.length; k++) {
1086-
dfs(grid, i + direction[k][0], j + direction[k][1]);
1101+
for (int[] d : direction) {
1102+
dfs(grid, i + d[0], j + d[1]);
10871103
}
10881104
}
10891105
```
@@ -1256,12 +1272,12 @@ private void dfs(int r, int c, boolean[][] canReach) {
12561272
Backtracking(回溯)属于 DFS。
12571273

12581274
- 普通 DFS 主要用在 **可达性问题** ,这种问题只需要执行到特点的位置然后返回即可。
1259-
- 而 Backtracking 主要用于求解 **排列组合** 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串,这种问题在执行到特定的位置返回时,在返回之后还会继续执行求解过程
1275+
- 而 Backtracking 主要用于求解 **排列组合** 问题,例如有 { 'a','b','c' } 三个字符,求解所有由这三个字符排列得到的字符串,这种问题在执行到特定的位置返回之后还会继续执行求解过程
12601276

12611277
因为 Backtracking 不是立即就返回,而要继续求解,因此在程序实现时,需要注意对元素的标记问题:
12621278

12631279
- 在访问一个新元素进入新的递归调用时,需要将新元素标记为已经访问,这样才能在继续递归调用时不用重复访问该元素;
1264-
- 但是在递归返回时,需要将该元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。
1280+
- 但是在递归返回时,需要将元素标记为未访问,因为只需要保证在一个递归链中不同时访问一个元素,可以访问已经访问过但是不在当前递归链中的元素。
12651281

12661282
**数字键盘组合**
12671283

@@ -1365,13 +1381,13 @@ public boolean exist(char[][] board, String word) {
13651381
boolean[][] visited = new boolean[m][n];
13661382
for (int i = 0; i < m; i++) {
13671383
for (int j = 0; j < n; j++) {
1368-
if (dfs(board, visited, word, 0, i, j)) return true;
1384+
if (backtracking(board, visited, word, 0, i, j)) return true;
13691385
}
13701386
}
13711387
return false;
13721388
}
13731389

1374-
private boolean dfs(char[][] board, boolean[][] visited, String word, int start, int r, int c) {
1390+
private boolean backtracking(char[][] board, boolean[][] visited, String word, int start, int r, int c) {
13751391
if (start == word.length()) {
13761392
return true;
13771393
}
@@ -1380,7 +1396,7 @@ private boolean dfs(char[][] board, boolean[][] visited, String word, int start,
13801396
}
13811397
visited[r][c] = true;
13821398
for (int[] d : direction) {
1383-
if (dfs(board, visited, word, start + 1, r + d[0], c + d[1])) {
1399+
if (backtracking(board, visited, word, start + 1, r + d[0], c + d[1])) {
13841400
return true;
13851401
}
13861402
}
@@ -1394,11 +1410,11 @@ private boolean dfs(char[][] board, boolean[][] visited, String word, int start,
13941410
[Leetcode : 257. Binary Tree Paths (Easy)](https://leetcode.com/problems/binary-tree-paths/description/)
13951411

13961412
```html
1397-
1
1413+
1
13981414
/ \
13991415
2 3
1400-
\
1401-
5
1416+
\
1417+
5
14021418
```
14031419

14041420
```html
@@ -1410,18 +1426,18 @@ public List<String> binaryTreePaths(TreeNode root) {
14101426
List<String> paths = new ArrayList();
14111427
if (root == null) return paths;
14121428
List<Integer> values = new ArrayList<>();
1413-
dfs(root, values, paths);
1429+
backtracking(root, values, paths);
14141430
return paths;
14151431
}
14161432

1417-
private void dfs(TreeNode node, List<Integer> values, List<String> paths) {
1433+
private void backtracking(TreeNode node, List<Integer> values, List<String> paths) {
14181434
if (node == null) return;
14191435
values.add(node.val);
14201436
if (isLeaf(node)) {
14211437
paths.add(buildPath(values));
14221438
} else {
1423-
dfs(node.left, values, paths);
1424-
dfs(node.right, values, paths);
1439+
backtracking(node.left, values, paths);
1440+
backtracking(node.right, values, paths);
14251441
}
14261442
values.remove(values.size() - 1);
14271443
}
@@ -1492,7 +1508,7 @@ private void backtracking(List<Integer> permuteList, boolean[] visited, int[] nu
14921508
[[1,1,2], [1,2,1], [2,1,1]]
14931509
```
14941510

1495-
题目描述:数组元素可能含有相同的元素,进行排列时就有可能出现 重复的排列,要求重复的排列只返回一个。
1511+
题目描述:数组元素可能含有相同的元素,进行排列时就有可能出现重复的排列,要求重复的排列只返回一个。
14961512

14971513
在实现上,和 Permutations 不同的是要先排序,然后在添加一个元素时,判断这个元素是否等于前一个元素,如果等于,并且前一个元素还未访问,那么就跳过这个元素。
14981514

0 commit comments

Comments
 (0)