diff --git a/notes/Java 虚拟机.md b/notes/Java 虚拟机.md
index cf9a8bbc..852e171c 100644
--- a/notes/Java 虚拟机.md
+++ b/notes/Java 虚拟机.md
@@ -142,7 +142,7 @@ Java 对引用的概念进行了扩充,引入四种强度不同的引用类型
**(一)强引用**
-只要强引用存在,垃圾回收器永远不会回收调掉被引用的对象。
+只要强引用存在,垃圾回收器永远不会回收被引用的对象。
使用 new 一个新对象的方式来创建强引用。
diff --git a/notes/Leetcode 题解.md b/notes/Leetcode 题解.md
index 73f19098..3520557c 100644
--- a/notes/Leetcode 题解.md
+++ b/notes/Leetcode 题解.md
@@ -127,7 +127,7 @@ public int arrangeCoins(int n) {
int l = 0, h = n;
while(l <= h){
int m = l + (h - l) / 2;
- long x = m * (m + 1L) / 2;
+ long x = m * (m + 1) / 2;
if(x == n) return m;
else if(x < n) l = m + 1;
else h = m - 1;
@@ -194,7 +194,7 @@ You need to output 2.
因为最小的孩子最容易得到满足,因此先满足最小孩子。给一个孩子的饼干应当尽量小又能满足该孩子,这样大饼干就能拿来给满足度比较大的孩子。
-证明:假设在某次选择中,贪心策略选择给第 i 个孩子分配第 m 个饼干,并且第 i 个孩子满足度最小,第 m 个饼干为可以满足第 i 个孩子的最小饼干,利用贪心策略最终可以满足 k 个孩子。假设最优策略在这次选择中给 i 个孩子分配第 n 个饼干,并且这个饼干大于第 m 个饼干。我们发现使用第 m 个饼干去替代第 n 个饼干完全不影响后续的结果,因此不存在比贪心策略更优的策略,即贪心策略就是最优策略。
+证明:假设在某次选择中,贪心策略选择给第 i 个孩子分配第 m 个饼干,并且第 i 个孩子满足度最小,第 m 个饼干为可以满足第 i 个孩子的最小饼干。假设最优策略在这次选择中给 i 个孩子分配第 n 个饼干,并且这个饼干大于第 m 个饼干。我们发现使用第 m 个饼干去替代第 n 个饼干完全不影响后续的结果,因此不存在比贪心策略更优的策略,即贪心策略就是最优策略。
```java
public int findContentChildren(int[] g, int[] s) {
@@ -1813,10 +1813,9 @@ dp[N] 即为所求。
```java
public int climbStairs(int n) {
- if(n == 1) return 1;
- if(n == 2) return 2;
- int pre1 = 2, pre2 = 1;
- for(int i = 2; i < n; i++){
+ if (n <= 2) return n;
+ int pre2 = 1, pre1 = 2;
+ for (int i = 2; i < n; i++) {
int cur = pre1 + pre2;
pre2 = pre1;
pre1 = cur;
@@ -1940,7 +1939,7 @@ dp[N] 即为所求。
-对于一个长度为 N 的序列,最长子序列并不一定会以 SN 为结尾,因此 dp[N] 不是序列的最长递增子序列的长度,需要遍历 dp 数组找出最大值才是所要的结果,即 max{ dp[i] | 1 <= i <= N} 即为所求。
+对于一个长度为 N 的序列,最长递增子序列并不一定会以 SN 为结尾,因此 dp[N] 不是序列的最长递增子序列的长度,需要遍历 dp 数组找出最大值才是所要的结果,即 max{ dp[i] | 1 <= i <= N} 即为所求。
**最长递增子序列**
@@ -1950,22 +1949,24 @@ dp[N] 即为所求。
public int lengthOfLIS(int[] nums) {
int n = nums.length;
int[] dp = new int[n];
- for(int i = 0; i < n; i++){
+ for (int i = 0; i < n; i++) {
int max = 1;
- for(int j = 0; j < i; j++){
- if(nums[i] > nums[j]) max = Math.max(max, dp[j] + 1);
+ for (int j = 0; j < i; j++) {
+ if (nums[i] > nums[j]) {
+ max = Math.max(max, dp[j] + 1);
+ }
}
dp[i] = max;
}
int ret = 0;
- for(int i = 0; i < n; i++){
+ for (int i = 0; i < n; i++) {
ret = Math.max(ret, dp[i]);
}
return ret;
}
```
-以上解法的时间复杂度为 O(n2) ,可以使用二分查找使得时间复杂度降低为 O(nlogn)。定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素,例如对于数组 [4,5,6,3],有
+以上解法的时间复杂度为 O(N2) ,可以使用二分查找将时间复杂度降低为 O(NlogN)。定义一个 tails 数组,其中 tails[i] 存储长度为 i + 1 的最长递增子序列的最后一个元素。如果有多个长度相等的最长递增子序列,那么 tails[i] 就取最小值。例如对于数组 [4,5,6,3],有
```html
len = 1 : [4], [5], [6], [3] => tails[0] = 3
@@ -1973,6 +1974,7 @@ len = 2 : [4, 5], [5, 6] => tails[1] = 5
len = 3 : [4, 5, 6] => tails[2] = 6
```
+
对于一个元素 x,
- 如果它大于 tails 数组所有的值,那么把它添加到 tails 后面,表示最长递增子序列长度加 1;
@@ -2094,7 +2096,7 @@ public int wiggleMaxLength(int[] nums) {
- 针对的是两个序列,求它们的最长公共子序列。
- 在最长递增子序列中,dp[i] 表示以 Si 为结尾的最长递增子序列长度,子序列必须包含 Si ;在最长公共子序列中,dp[i][j] 表示 S1 中前 i 个字符与 S2 中前 j 个字符的最长公共子序列长度,不一定包含 S1i 和 S2j 。
-- 由于 2 ,在求最终解时,最长公共子序列中 dp[N][M] 就是最终解,而最长递增子序列中 dp[N] 不是最终解,因为以 SN 为结尾的最长递增子序列不一定是整个序列最长递增子序列,需要遍历一遍 dp 数组找到最大者。
+- 在求最终解时,最长公共子序列中 dp[N][M] 就是最终解,而最长递增子序列中 dp[N] 不是最终解,因为以 SN 为结尾的最长递增子序列不一定是整个序列最长递增子序列,需要遍历一遍 dp 数组找到最大者。
```java
public int lengthOfLCS(int[] nums1, int[] nums2) {
@@ -2114,7 +2116,7 @@ public int lengthOfLCS(int[] nums1, int[] nums2) {
有一个容量为 N 的背包,要用这个背包装下物品的价值最大,这些物品有两个属性:体积 w 和价值 v。
-定义一个二维数组 dp 存储最大价值,其中 dp[i][j] 表示体积不超过 j 的情况下,前 i 件物品能达到的最大价值。设第 i 件物品体积为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论:
+定义一个二维数组 dp 存储最大价值,其中 dp[i][j] 表示前 i 件物品体积不超过 j 的情况下能达到的最大价值。设第 i 件物品体积为 w,价值为 v,根据第 i 件物品是否添加到背包中,可以分两种情况讨论:
- 第 i 件物品没添加到背包,总体积不超过 j 的前 i 件物品的最大价值就是总体积不超过 j 的前 i-1 件物品的最大价值,dp[i][j] = dp[i-1][j]。
- 第 i 件物品添加到背包中,dp[i][j] = dp[i-1][j-w] + v。
@@ -2306,9 +2308,7 @@ public int findTargetSumWays(int[] nums, int S) {
}
private int findTargetSumWays(int[] nums, int start, int S) {
- if (start == nums.length) {
- return S == 0 ? 1 : 0;
- }
+ if (start == nums.length) return S == 0 ? 1 : 0;
return findTargetSumWays(nums, start + 1, S + nums[start]) + findTargetSumWays(nums, start + 1, S - nums[start]);
}
```
@@ -2362,7 +2362,7 @@ return -1.
题目描述:给一些面额的硬币,要求用这些硬币来组成给定面额的钱数,并且使得硬币数量最少。硬币可以重复使用。
-这是一个完全背包问题。
+这是一个完全背包问题,完全背包问题和 0-1 背包问题在实现上的区别在于,0-1 背包遍历物品的循环在外侧,而完全背包问题遍历物品的循环在内侧,在内侧体现出物品可以使用多次。
```java
public int coinChange(int[] coins, int amount) {
@@ -2371,7 +2371,7 @@ public int coinChange(int[] coins, int amount) {
Arrays.fill(dp, amount + 1);
dp[0] = 0;
for (int i = 1; i <= amount; i++) {
- for (int c : coins) {
+ for (int c : coins) { // 硬币可以使用多次
if (c <= i) {
dp[i] = Math.min(dp[i], dp[i - c] + 1);
}
@@ -2584,10 +2584,31 @@ public int minDistance(String word1, String word2) {
}
```
-**修改一个字符串称为另一个字符串**
+**修改一个字符串成为另一个字符串**
[Leetcode : 72. Edit Distance (Hard)](https://leetcode.com/problems/edit-distance/description/)
+```html
+Example 1:
+
+Input: word1 = "horse", word2 = "ros"
+Output: 3
+Explanation:
+horse -> rorse (replace 'h' with 'r')
+rorse -> rose (remove 'r')
+rose -> ros (remove 'e')
+Example 2:
+
+Input: word1 = "intention", word2 = "execution"
+Output: 5
+Explanation:
+intention -> inention (remove 't')
+inention -> enention (replace 'i' with 'e')
+enention -> exention (replace 'n' with 'x')
+exention -> exection (replace 'n' with 'c')
+exection -> execution (insert 'u')
+```
+
```java
public int minDistance(String word1, String word2) {
if (word1 == null || word2 == null) {
@@ -2646,12 +2667,12 @@ public int numSquares(int n) {
List squareList = generateSquareList(n);
int[] dp = new int[n + 1];
for (int i = 1; i <= n; i++) {
- int max = Integer.MAX_VALUE;
+ int min = Integer.MAX_VALUE;
for (int square : squareList) {
if (square > i) break;
- max = Math.min(max, dp[i - square] + 1);
+ min = Math.min(min, dp[i - square] + 1);
}
- dp[i] = max;
+ dp[i] = min;
}
return dp[n];
}
@@ -2767,7 +2788,7 @@ public int minPathSum(int[][] grid) {
题目描述:交易之后需要有一天的冷却时间。
-
+
```java
public int maxProfit(int[] prices) {
@@ -2806,7 +2827,7 @@ The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
题目描述:每交易一次,都要支付一定的费用。
-
+
```java
public int maxProfit(int[] prices, int fee) {
@@ -2833,7 +2854,7 @@ public int maxProfit(int[] prices, int fee) {
只进行一次交易。
-只要记录前面的最小价格,将这个最小价格作为买入价格,然后将当前的价格作为售出价格,查看这个价格是否是当前的最大价格。
+只要记录前面的最小价格,将这个最小价格作为买入价格,然后将当前的价格作为售出价格,查看当前收益是不是最大收益。
```java
public int maxProfit(int[] prices) {
diff --git a/pics/61942711-45a0-4e11-bbc9-434e31436f33.png b/pics/61942711-45a0-4e11-bbc9-434e31436f33.png
new file mode 100644
index 00000000..8f093ef6
Binary files /dev/null and b/pics/61942711-45a0-4e11-bbc9-434e31436f33.png differ
diff --git a/pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png b/pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png
new file mode 100644
index 00000000..03b37a61
Binary files /dev/null and b/pics/a3da4342-078b-43e2-b748-7e71bec50dc4.png differ