Skip to content

Commit 34c5cc6

Browse files
committed
update some stock problem solution
1 parent c53001c commit 34c5cc6

File tree

14 files changed

+358
-38
lines changed

14 files changed

+358
-38
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ LeetCode of algorithms with golang solution(updating:smiley:).
4242

4343
## Community
4444

45+
* [ACWING](https://www.acwing.com/) 一些算法竞赛大佬创建的平台,挺适合入门的。
4546
* [leetbook](https://github.com/hk029/leetbook) 某位大佬写的Leetcode题解,不过已经不更新了
4647
* [LeetCode-in-Go](https://github.com/aQuaYi/LeetCode-in-Go) 某位算法大佬的Golang题解
4748

src/0072.Edit-Distance/README.md

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,62 @@
1-
# [1. Add Sum][title]
1+
# [72. Edit Distance][title]
22

33
## Description
44

5-
Given two binary strings, return their sum (also a binary string).
5+
Given two words word1 and word2, find the minimum number of operations required to convert word1 to word2.
66

7-
The input strings are both **non-empty** and contains only characters `1` or `0`.
7+
You have the following 3 operations permitted on a word:
8+
9+
- Insert a character
10+
- Delete a character
11+
- Replace a character
812

913
**Example 1:**
1014

1115
```
12-
Input: a = "11", b = "1"
13-
Output: "100"
16+
Input: word1 = "horse", word2 = "ros"
17+
Output: 3
18+
Explanation:
19+
horse -> rorse (replace 'h' with 'r')
20+
rorse -> rose (remove 'r')
21+
rose -> ros (remove 'e')
1422
```
1523

1624
**Example 2:**
1725

1826
```
19-
Input: a = "1010", b = "1011"
20-
Output: "10101"
27+
Input: word1 = "intention", word2 = "execution"
28+
Output: 5
29+
Explanation:
30+
intention -> inention (remove 't')
31+
inention -> enention (replace 'i' with 'e')
32+
enention -> exention (replace 'n' with 'x')
33+
exention -> exection (replace 'n' with 'c')
34+
exection -> execution (insert 'u')
2135
```
2236

2337
**Tags:** Math, String
2438

2539
## 题意
26-
>给你两个二进制串,求其和的二进制串
40+
>给定两个单词 word1 和 word2 ,请问最少需要进行多少次操作可以将 word1 变成 word2
2741
2842
## 题解
2943

3044
### 思路1
31-
> 按照小学算数那么来做,用 `carry` 表示进位,从后往前算,依次往前,每算出一位就插入到最前面即可,直到把两个二进制串都遍历完即可。
45+
> (动态规划) O(n2)
46+
47+
经典的编辑距离问题。
48+
49+
状态表示:`f[i,j]` 表示将 `word1` 的前 `i` 个字符变成 `word2` 的前 `j` 个字符,最少需要进行多少次操作。
50+
状态转移,一共有四种情况:
51+
52+
-`word1[i]` 删除或在`word2[j]`后面添加`word1[i]`,则其操作次数等于`f[i−1,j]+1`
53+
-`word2[j]`删除或在`word1[i]`后面添加`word2[j]`,则其操作次数等于 `f[i,j−1]+1`
54+
- 如果`word1[i]=word2[j]`,则其操作次数等于 `f[i−1,j−1]`
55+
- 如果`word1[i]≠word2[j]`,则其操作次数等于 `f[i−1,j−1]+1`
56+
57+
> 时间复杂度分析:
58+
59+
- 状态数 O(n2)O(n2),状态转移复杂度是 O(1)O(1),所以总时间复杂度是 O(n2)O(n2)。
3260

3361
```go
3462

src/0121.Best-Time-to-Buy-and-Sell-Stock/README.md

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,40 @@ Output: "10101"
2323
**Tags:** Math, String
2424

2525
## 题意
26-
>只允许买卖一次
26+
>假设你有一个数组,其中第i个元素表示第i天某个股票的价格。
27+
如果您只允许完成至多一笔交易(即买入一只股票并卖出一只股票),则设计一种算法以找到最大利润。
28+
必须先购买股票再出售股票。
2729

2830
## 题解
2931

3032
### 思路1
31-
> 按照小学算数那么来做,用 `carry` 表示进位,从后往前算,依次往前,每算出一位就插入到最前面即可,直到把两个二进制串都遍历完即可。
33+
> 贪心
3234
33-
```go
35+
- 遍历一次即可得出结果
3436

37+
```go
38+
func maxProfit2(prices []int) int {
39+
profit, low := 0, prices[0]
40+
for i := 0; i < len(prices); i++ {
41+
profit = max(profit, prices[i]-low)
42+
low = min(low, prices[i])
43+
}
44+
return profit
45+
}
46+
47+
func min(x, y int) int {
48+
if x > y {
49+
return y
50+
}
51+
return x
52+
}
53+
54+
func max(x, y int) int {
55+
if x > y {
56+
return x
57+
}
58+
return y
59+
}
3560
```
3661

3762
### 思路2

src/0121.Best-Time-to-Buy-and-Sell-Stock/Solution.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package Solution
22

3-
import "math"
4-
53
/**
64
持有一股
75
买卖一次
@@ -28,16 +26,24 @@ func maxProfit1(prices []int) int {
2826
// Greedy
2927
// 扫描一遍
3028
func maxProfit2(prices []int) int {
31-
min := math.MaxInt32
32-
max := 0
33-
29+
profit, low := 0, prices[0]
3430
for i := 0; i < len(prices); i++ {
35-
if prices[i] < min {
36-
min = prices[i]
37-
} else if max < prices[i]-min {
38-
max = prices[i] - min
39-
}
31+
profit = max(profit, prices[i]-low)
32+
low = min(low, prices[i])
33+
}
34+
return profit
35+
}
36+
37+
func min(x, y int) int {
38+
if x > y {
39+
return y
4040
}
41+
return x
42+
}
4143

42-
return max
44+
func max(x, y int) int {
45+
if x > y {
46+
return x
47+
}
48+
return y
4349
}

src/0122.Best-Time-To-Buy-And-Sell-Stock-II/README.md

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,59 @@ Output: "10101"
2323
**Tags:** Math, String
2424

2525
## 题意
26-
>给你两个二进制串,求其和的二进制串。
27-
26+
>假设你有一个数组,其中第i个元素表示第i天某个股票的价格。
27+
设计一种算法以找到最大利润,可以完成任意多次交易,但必须先购买股票再出售股票,不能同时多次交易。
28+
2829
## 题解
2930

3031
### 思路1
31-
> 按照小学算数那么来做,用 `carry` 表示进位,从后往前算,依次往前,每算出一位就插入到最前面即可,直到把两个二进制串都遍历完即可。
32+
> (动态规划) O(n)
3233
33-
```go
34+
- 设计状态`f[i]`表示第`i`天,当前不持有股票的最大收益;`g[i]`表示第`i`天,当前持有股票的最大收益。
35+
- 状态转移为`f[i] = max(f[i - 1], g[i - 1] + prices[i])`,表示构成第i天不持有股票有两种方式,一种是前一天也不持有,另一种是前一天持有且这一天售出;二者取最大值。
36+
- `g[i] = max(g[i - 1], f[i - 1] - prices[i])`,表示构成第i天持有股票有两种方式,一种是前一天持有,另一种是前一天不持有,但这一天刚刚买入。
37+
- 最终答案为`f[n - 1]`,即最后一天不持有股票的最大收益。
3438

39+
```go
40+
func maxProfit2(prices []int) int {
41+
// 初始化DP
42+
n := len(prices)
43+
dp := make([][]int, 0)
44+
for i := 0; i <= n; i++ {
45+
dp = append(dp, make([]int, 2))
46+
}
47+
dp[0][0], dp[0][1] = 0, math.MinInt32
48+
profit_max := 0
49+
for i := 0; i < n; i++ {
50+
dp[i+1][0] = max(dp[i][1]+prices[i], dp[i][0])
51+
dp[i+1][1] = max(dp[i][0]-prices[i], dp[i][1])
52+
53+
profit_max = max(profit_max, dp[i+1][0])
54+
profit_max = max(profit_max, dp[i+1][1])
55+
}
56+
return profit_max
57+
}
3558
```
3659

3760
### 思路2
38-
> 思路2
39-
```go
61+
> 贪心:遍历一次数组,低进高出,把正的价格差相加起来就是最终利润。
62+
63+
遍历一次数组,低进高出,把正的价格差相加起来就是最终利润。
64+
- 递增,如`[1,2,3]`,那么1买3卖 与 每天都买入卖出 等价
65+
- 递减,如`[3,2,1]`,赚钱是赚不了的
66+
- 先高再低,如`[1,3,2]`,那么只能在1买3卖捞一笔
67+
- 先低再高,如`[2,1,3]`,那么同样只能在1买3卖捞一笔
4068

69+
```go
70+
func maxProfit(prices []int) int {
71+
profit := 0
72+
for i := 1; i < len(prices); i++ {
73+
if prices[i] > prices[i-1] {
74+
profit += prices[i] - prices[i-1]
75+
}
76+
}
77+
return profit
78+
}
4179
```
4280

4381
## 结语

src/0122.Best-Time-To-Buy-And-Sell-Stock-II/Solution.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ import (
1111

1212
// Greedy
1313
func maxProfit(prices []int) int {
14-
maxprofix := 0
14+
profit := 0
1515
for i := 1; i < len(prices); i++ {
1616
if prices[i] > prices[i-1] {
17-
maxprofix += prices[i] - prices[i-1]
17+
profit += prices[i] - prices[i-1]
1818
}
1919
}
20-
return maxprofix
20+
return profit
2121
}
2222

2323
// DP
@@ -26,6 +26,7 @@ func maxProfit(prices []int) int {
2626
//dp[i][0] = max(dp[i-1][1]+price[i],dp[i-1][0]) --> Sell on day i or do nothing
2727
//dp[i][1] = max(dp[i-1][0])-price[i],dp[i-1][1]) --> Buy on day i or do nothing
2828
//dp[0][0]=0,dp[0][1]=INT_MIN
29+
2930
func maxProfit2(prices []int) int {
3031
// 初始化DP
3132
n := len(prices)

src/0123.Best-Time-to-Buy-and-Sell-Stock-III/README.md

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,20 @@ Explanation: In this case, no transaction is done, i.e. max profit = 0.
3737
**Tags:** Math, String
3838

3939
## 题意
40-
>买卖股票,持有一股,买卖2此
40+
>给你一个数组,第 ii 个元素表示第 ii 天股票的价格。
41+
你最多可以交易两次。
42+
请设计一个算法,求最大收益。
43+
44+
> 注意:必须先买再卖,且每天只能买或者卖一次。
4145
4246
## 题解
4347

4448
### 思路1
45-
>
49+
> 在整个区间的每一点切开, 然后分别计算左子区间和右子区间的最大值,然后再用O(n)时间找到整个区间的最大值。
50+
51+
- 遍历一遍数组,求`[0,i−1][0,i−1`]区间的最大利润`f(i)`,具体做法是找当前最低价格`low`,判断是要以`low`买入当天卖出,还是不动
52+
- 从后往前遍历,求`[i,n−1][i,n−1]`区间的最大利润`g(i)`,具体做法是找当前最高价格`high`,判断是要当天买入以`high`卖出,还是不动
53+
- 遍历,求最大利润`max(f(i)+g(i))`
4654

4755
```go
4856
func maxProfit(prices []int) int {

src/0123.Best-Time-to-Buy-and-Sell-Stock-III/Solution.go

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package Solution
22

33
import "math"
44

5-
func maxProfit(prices []int) int {
5+
func maxProfit2(prices []int) int {
66
t1_b, t1_s, t2_b, t2_s := math.MinInt32, 0, math.MinInt32, 0
77

88
for _, v := range prices {
@@ -19,3 +19,29 @@ func max(a, b int) int {
1919
}
2020
return a
2121
}
22+
func min(x, y int) int {
23+
if x > y {
24+
return y
25+
}
26+
return y
27+
}
28+
29+
func maxProfit(prices []int) int {
30+
g, f := make([]int, len(prices)), make([]int, len(prices))
31+
ans, n, low := 0, len(prices), prices[0]
32+
33+
for i := 1; i < n; i++ {
34+
low = min(low, prices[i])
35+
f[i] = max(f[i-1], prices[i]-low)
36+
}
37+
high := prices[n-1]
38+
for i := n - 2; i >= 0; i-- {
39+
high = max(high, prices[i])
40+
g[i] = max(g[i+1], high-prices[i])
41+
}
42+
43+
for i := 0; i < n; i++ {
44+
ans = max(ans, f[i]+g[i])
45+
}
46+
return ans
47+
}

src/0123.Best-Time-to-Buy-and-Sell-Stock-III/Solution_test.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,30 @@ func TestSolution1(t *testing.T) {
3030
}
3131
}
3232

33+
func TestSolution2(t *testing.T) {
34+
// 测试用例
35+
cases := []struct {
36+
name string
37+
inputs []int
38+
expect int
39+
}{
40+
{"TestCase", []int{3, 3, 5, 0, 0, 3, 1, 4}, 6},
41+
{"TestCase", []int{1, 2, 3, 4, 5}, 4},
42+
{"TestCase", []int{7, 6, 4, 3, 1}, 0},
43+
}
44+
45+
// 开始测试
46+
for i, c := range cases {
47+
t.Run(c.name+strconv.Itoa(i), func(t *testing.T) {
48+
got := maxProfit2(c.inputs)
49+
if !reflect.DeepEqual(got, c.expect) {
50+
t.Fatalf("expected: %v, but got: %v, with inputs: %v",
51+
c.expect, got, c.inputs)
52+
}
53+
})
54+
}
55+
}
56+
3357
// 压力测试
3458
func BenchmarkSolution(b *testing.B) {
3559

src/0300.Longest-Increasing-Subsequence/README.md

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,39 @@ Explanation: The longest increasing subsequence is [2,3,7,101], therefore the le
2424
## 题解
2525

2626
### 思路1
27-
> 按照小学算数那么来做,用 `carry` 表示进位,从后往前算,依次往前,每算出一位就插入到最前面即可,直到把两个二进制串都遍历完即可。
27+
> (动态规划)O(n2)
2828
29-
```go
29+
- 用数组`dp[i]`记录以`nums[i]`结尾(即`nums[i]`为最后一个数字)的最长递增子序列的长度,则递推方程为`dp[i]=max(dp[j]+1)`,其中要求`1≤j<i``nums[j]<nums[i]`
30+
31+
> 时间复杂度分析:
3032
33+
- 对每个i(1≤i≤n),都需要从1遍历到i,则时间复杂度为O(n2),空间复杂度的话需要一个额外的dp数组,空间复杂度为O(n2)。
34+
35+
> Code
36+
```go
37+
func lengthOfLIS(nums []int) int {
38+
if len(nums) == 0 {
39+
return 0
40+
}
41+
dp, ans := make([]int, len(nums)), 1
42+
43+
for i := 0; i < len(nums); i++ {
44+
dp[i] = 1
45+
}
46+
47+
for i := 1; i < len(nums); i++ {
48+
for j := 0; j < i; j++ {
49+
if nums[i] > nums[j] {
50+
dp[i] = max(dp[i], dp[j]+1)
51+
}
52+
//fmt.Println(i, j, ans, dp, nums)
53+
}
54+
if dp[i] > ans {
55+
ans = dp[i]
56+
}
57+
}
58+
return ans
59+
}
3160
```
3261

3362
### 思路2

0 commit comments

Comments
 (0)