diff --git a/notes/剑指 offer 题解.md b/notes/剑指 offer 题解.md
index edb0006c..f4927da8 100644
--- a/notes/剑指 offer 题解.md
+++ b/notes/剑指 offer 题解.md
@@ -192,9 +192,9 @@ public boolean Find(int target, int[][] matrix) {
在字符串尾部填充任意字符,使得字符串的长度等于字符串替换之后的长度。因为一个空格要替换成三个字符(%20),因此当遍历到一个空格时,需要在尾部填充两个任意字符。
-令 idxOfOld 指向字符串原来的末尾位置,idxOfNew 指向字符串现在的末尾位置。idxOfOld 和 idxOfNew 从后向前遍历,当 idxOfOld 遍历到一个空格时,就需要令 idxOfNew 指向的位置依次填充 02%(注意是逆序的),否则就填充上 idxOfOld 指向字符的值。
+令 P1 指向字符串原来的末尾位置,P2 指向字符串现在的末尾位置。P1 和 P2从后向前遍历,当 P1 遍历到一个空格时,就需要令 P2 指向的位置依次填充 02%(注意是逆序的),否则就填充上 P1 指向字符的值。
-从后向前遍是为了在改变 idxOfNew 所指向的内容时,不会影响到 idxOfOld 遍历原来字符串的内容。
+从后向前遍是为了在改变 P2 所指向的内容时,不会影响到 P1 遍历原来字符串的内容。
复杂度:O(N) + O(1)
@@ -839,7 +839,7 @@ public int NumberOf1(int n) {
-因为 (x\*x)n/2 可以通过递归求解,并且每递归一次,n 都减小一半,因此整个算法的时间复杂度为 O(logn)。
+因为 (x\*x)n/2 可以通过递归求解,并且每递归一次,n 都减小一半,因此整个算法的时间复杂度为 O(logN)。
```java
public double Power(double base, int exponent) {
@@ -976,8 +976,8 @@ if p.charAt(j) == s.charAt(i) : then dp[i][j] = dp[i-1][j-1];
if p.charAt(j) == '.' : then dp[i][j] = dp[i-1][j-1];
if p.charAt(j) == '*' :
if p.charAt(j-1) != s.charAt(i) : then dp[i][j] = dp[i][j-2] // a* only counts as empty
- if p.charAt(j-1) == s.charAt(i)
- or p.charAt(i-1) == '.' :
+ if p.charAt(j-1) == s.charAt(i) or
+ p.charAt(i-1) == '.' :
then dp[i][j] = dp[i-1][j] // a* counts as multiple a
or dp[i][j] = dp[i][j-1] // a* counts as single a
or dp[i][j] = dp[i][j-2] // a* counts as empty
@@ -1085,7 +1085,7 @@ public ListNode FindKthToTail(ListNode head, int k) {
## 解题思路
-使用双指针,一个指针 fast 每次移动两个节点,一个指针 slow 每次移动一个节点。因为存在环,所以两个指针必定相遇在环中的某个节点上。此时 fast 移动的节点数为 x+2y+z,slow 为 x+y,由于 fast 速度比 slow 快一倍,因此 x+2y+z=2(x+y),得到 x=z。
+使用双指针,一个指针 fast 每次移动两个节点,一个指针 slow 每次移动一个节点。因为存在环,所以两个指针必定相遇在环中的某个节点上。假设相遇点在下图的 z1 位置,此时 fast 移动的节点数为 x+2y+z,slow 为 x+y,由于 fast 速度比 slow 快一倍,因此 x+2y+z=2(x+y),得到 x=z。
在相遇点,slow 要到环的入口点还需要移动 z 个节点,如果让 fast 重新从头开始移动,并且速度变为每次移动一个节点,那么它到环入口点还需要移动 x 个节点。在上面已经推导出 x=z,因此 fast 和 slow 将在环入口点相遇。
@@ -1093,22 +1093,21 @@ public ListNode FindKthToTail(ListNode head, int k) {
```java
public ListNode EntryNodeOfLoop(ListNode pHead) {
- if (pHead == null)
+ if (pHead == null || pHead.next == null)
return null;
ListNode slow = pHead, fast = pHead;
while (fast != null && fast.next != null) {
fast = fast.next.next;
slow = slow.next;
- if (slow == fast) {
- fast = pHead;
- while (slow != fast) {
- slow = slow.next;
- fast = fast.next;
- }
- return slow;
- }
+ if (slow == fast)
+ break;
}
- return null;
+ fast = pHead;
+ while (slow != fast) {
+ slow = slow.next;
+ fast = fast.next;
+ }
+ return slow;
}
```
@@ -1782,7 +1781,7 @@ public ArrayList GetLeastNumbers_Solution(int[] nums, int k) {
if (k > nums.length || k <= 0)
return ret;
int kthSmallest = findKthSmallest(nums, k - 1);
- // findKthSmallest 会让改变数组,使得前 k 个数都是最小的 k 个数
+ // findKthSmallest 会改变数组,使得前 k 个数都是最小的 k 个数
for (int i = 0; i < k; i++)
ret.add(nums[i]);
return ret;
@@ -1902,22 +1901,18 @@ public class Solution {
## 解题思路
```java
-public class Solution {
- private int[] cnts = new int[256];
- private Queue queue = new LinkedList<>();
+private int[] cnts = new int[256];
+private Queue queue = new LinkedList<>();
- public void Insert(char ch) {
- cnts[ch]++;
- queue.add(ch);
- while (!queue.isEmpty() && cnts[queue.peek()] > 1)
- queue.poll();
- }
+public void Insert(char ch) {
+ cnts[ch]++;
+ queue.add(ch);
+ while (!queue.isEmpty() && cnts[queue.peek()] > 1)
+ queue.poll();
+}
- public char FirstAppearingOnce() {
- if (queue.isEmpty())
- return '#';
- return queue.peek();
- }
+public char FirstAppearingOnce() {
+ return queue.isEmpty() ? '#' : queue.peek();
}
```
@@ -1932,17 +1927,17 @@ public class Solution {
## 解题思路
```java
- public int FindGreatestSumOfSubArray(int[] nums) {
- if (nums.length == 0)
- return 0;
- int ret = Integer.MIN_VALUE;
- int sum = 0;
- for (int val : nums) {
- sum = sum <= 0 ? val : sum + val;
- ret = Math.max(ret, sum);
- }
- return ret;
- }
+public int FindGreatestSumOfSubArray(int[] nums) {
+ if (nums == null || nums.length == 0)
+ return 0;
+ int ret = Integer.MIN_VALUE;
+ int sum = 0;
+ for (int val : nums) {
+ sum = sum <= 0 ? val : sum + val;
+ ret = Math.max(ret, sum);
+ }
+ return ret;
+}
```
# 43. 从 1 到 n 整数中 1 出现的次数
@@ -2031,6 +2026,8 @@ private int beginNumber(int digit) {
```java
public String PrintMinNumber(int[] numbers) {
+ if (numbers == null || numbers.length == 0)
+ return "";
int n = numbers.length;
String[] nums = new String[n];
for (int i = 0; i < n; i++)
@@ -2196,7 +2193,7 @@ public int FirstNotRepeatingChar(String str) {
}
```
-以上实现的空间复杂度还不是最优的。考虑到只需要找到只出现一次的字符,那么我们只需要统计的次数信息只有 0,1,更大,那么使用两个比特位就能存储这些信息。
+以上实现的空间复杂度还不是最优的。考虑到只需要找到只出现一次的字符,那么我们只需要统计的次数信息只有 0,1,更大,使用两个比特位就能存储这些信息。
```java
public int FirstNotRepeatingChar(String str) {
@@ -2743,7 +2740,7 @@ public int LastRemaining_Solution(int n, int m) {
## 解题思路
-使用贪心策略,假设第 i 轮进行卖出操作,买入操作价格应该是 i 之前并且价格最低。
+使用贪心策略,假设第 i 轮进行卖出操作,买入操作价格应该在 i 之前并且价格最低。
```java
public int maxProfit(int[] prices) {
@@ -2799,7 +2796,7 @@ a ^ b 表示没有考虑进位的情况下两数的和,(a & b) << 1 就是进
递归会终止的原因是 (a & b) << 1 最右边会多一个 0,那么继续递归,进位最右边的 0 会慢慢增多,最后进位会变为 0,递归终止。
```java
-public int Add(int num1,int num2) {
+public int Add(int num1, int num2) {
return num2 == 0 ? num1 : Add(num1 ^ num2, (num1 & num2) << 1);
}
```
@@ -2848,17 +2845,17 @@ Output:
```java
public int StrToInt(String str) {
- if (str.length() == 0)
+ if (str == null || str.length() == 0)
return 0;
- char[] chars = str.toCharArray();
- boolean isNegative = chars[0] == '-';
+ boolean isNegative = str.charAt(0) == '-';
int ret = 0;
- for (int i = 0; i < chars.length; i++) {
- if (i == 0 && (chars[i] == '+' || chars[i] == '-'))
+ for (int i = 0; i < str.length(); i++) {
+ char c = str.charAt(i);
+ if (i == 0 && (c == '+' || c == '-'))
continue;
- if (chars[i] < '0' || chars[i] > '9')
+ if (c < '0' || c > '9')
return 0; // 非法输入
- ret = ret * 10 + (chars[i] - '0');
+ ret = ret * 10 + (c - '0');
}
return isNegative ? -ret : ret;
}
@@ -2874,7 +2871,7 @@ public int StrToInt(String str) {
[Leetcode : 235. Lowest Common Ancestor of a Binary Search Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/description/)
-二叉查找树中,两个节点 p, q 的公共祖先 root 满足 p.val <= root.val && root.val <= q.val,只要找到满足这个条件的最低层节点即可。换句话说,应该先考虑子树的解而不是根节点的解,二叉树的后序遍历操作满足这个特性。在本题中我们可以利用后序遍历的特性,先在左右子树中查找解,最后再考虑根节点的解。
+二叉查找树中,两个节点 p, q 的公共祖先 root 满足 root.val >= p.val && root.val <= q.val。
```java
public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {