Skip to content

Commit 9451531

Browse files
author
lucifer
committed
2 parents 61a38c4 + f9e7d1f commit 9451531

10 files changed

+275
-190
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ leetcode 题解,记录自己的 leetcode 解题之路。
193193
- [0139.word-break](./problems/139.word-break.md)
194194
- [0144.binary-tree-preorder-traversal](./problems/144.binary-tree-preorder-traversal.md)
195195
- [0150.evaluate-reverse-polish-notation](./problems/150.evaluate-reverse-polish-notation.md)
196-
- [0152.maximum-product-subarray](./problems/152.maximum-product-subarray.md)
196+
- [0152.maximum-product-subarray](./problems/152.maximum-product-subarray.md) 🖊
197197
- [0199.binary-tree-right-side-view](./problems/199.binary-tree-right-side-view.md)
198198
- [0200.number-of-islands](./problems/200.number-of-islands.md) 🆕
199199
- [0201.bitwise-and-of-numbers-range](./problems/201.bitwise-and-of-numbers-range.md) 🖊

daily/2019-08-09.md

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,26 +20,28 @@
2020
解释: 因为路径 1→3→1→1→1 的总和最小。
2121
```
2222
## 参考答案
23-
动态规划求解,时间复杂度O(n*m)
24-
>
25-
我们新建一个额外的dp数组,与原矩阵大小相同。在这个矩阵中,dp(i,j)表示从坐标(i,j)到右下角的最小路径权值。我们初始化右下角的dp值为对应的原矩阵值,然后去填整个矩阵,对于每个元素考虑移动到右边或者下面,因此获得最小路径和我们有如下递推公式:`dp(i,j)=grid(i,j)+min(dp(i+1,j),dp(i,j+1))`
23+
24+
我们新建一个额外的dp数组,与原矩阵大小相同。在这个矩阵中,dp(i,j)表示从原点到坐标(i,j)的最小路径和。我们初始化dp值为对应的原矩阵值,然后去填整个矩阵,对于每个元素考虑从上方移动过来还是从左方移动过来,因此获得最小路径和我们有如下递推公式:`dp(i,j)=grid(i,j)+min(dp(i-1,j),dp(i,j-1))`
25+
26+
27+
我们可以使用原地算法,这样就不需要开辟dp数组,空间复杂度可以降低到$O(1)$。
28+
2629
```c++
2730
class Solution {
2831
public:
2932
int minPathSum(vector<vector<int>>& grid) {
30-
//剪枝
3133
int n = grid.size();
3234
if(n==0)
3335
return 0;
3436
int m = grid[0].size();
3537
if(m==0)
3638
return 0;
37-
//初始化第一列
39+
//初始化第一行
3840
for(int i=1;i<m;i++)
3941
{
4042
grid[0][i] += grid[0][i-1];
4143
}
42-
//初始化第一排
44+
//初始化第一列
4345
for(int i=1;i<n;i++)
4446
{
4547
grid[i][0] += grid[i-1][0];
@@ -57,6 +59,11 @@ public:
5759
}
5860
};
5961
```
62+
63+
64+
**复杂度分析**
65+
- 时间复杂度:$O(M * N)$
66+
- 空间复杂度:$O(1)$
6067
## 其他优秀解答
6168
62-
> 暂缺
69+
> 暂缺

problems/152.maximum-product-subarray.md

Lines changed: 66 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -49,52 +49,75 @@ var maxProduct = function(nums) {
4949

5050
因此我们需要同时记录乘积最大值和乘积最小值,然后比较元素和这两个的乘积,去不断更新最大值。
5151

52-
![152.maximum-product-subarray](../assets/problems/152.maximum-product-subarray.png)
52+
![](https://tva1.sinaimg.cn/large/0082zybply1gcatuvun39j30gr08kt9l.jpg)
5353

5454
这种思路的解法由于只需要遍历一次,其时间复杂度是O(n),代码见下方代码区。
55+
5556
## 关键点
5657

5758
- 同时记录乘积最大值和乘积最小值
58-
5959
## 代码
6060

61+
代码支持:Python3,JavaScript
62+
63+
64+
65+
Python3 Code:
66+
67+
68+
```python
69+
70+
71+
class Solution:
72+
def maxProduct(self, nums: List[int]) -> int:
73+
n = len(nums)
74+
max__dp = [1] * (n + 1)
75+
min_dp = [1] * (n + 1)
76+
ans = float('-inf')
77+
78+
for i in range(1, n + 1):
79+
max__dp[i] = max(max__dp[i - 1] * nums[i - 1],
80+
min_dp[i - 1] * nums[i - 1], nums[i - 1])
81+
min_dp[i] = min(max__dp[i - 1] * nums[i - 1],
82+
min_dp[i - 1] * nums[i - 1], nums[i - 1])
83+
ans = max(ans, max__dp[i])
84+
return ans
85+
```
86+
87+
88+
**复杂度分析**
89+
- 时间复杂度:$O(N)$
90+
- 空间复杂度:$O(N)$
91+
92+
93+
当我们知道动态转移方程的时候,其实应该发现了。我们的dp[i] 只和 dp[i - 1]有关,这是一个空间优化的信号,告诉我们`可以借助两个额外变量记录即可`
94+
95+
96+
Python3 Code:
97+
98+
99+
```python
100+
101+
class Solution:
102+
def maxProduct(self, nums: List[int]) -> int:
103+
n = len(nums)
104+
a = b = 1
105+
ans = float('-inf')
106+
107+
for i in range(1, n + 1):
108+
temp = a
109+
a = max(a * nums[i - 1],
110+
b * nums[i - 1], nums[i - 1])
111+
b = min(temp * nums[i - 1],
112+
b * nums[i - 1], nums[i - 1])
113+
ans = max(ans, a)
114+
return ans
115+
116+
```
117+
118+
JavaScript Code:
119+
61120
```js
62-
/*
63-
* @lc app=leetcode id=152 lang=javascript
64-
*
65-
* [152] Maximum Product Subarray
66-
*
67-
* https://leetcode.com/problems/maximum-product-subarray/description/
68-
*
69-
* algorithms
70-
* Medium (28.61%)
71-
* Total Accepted: 202.8K
72-
* Total Submissions: 700K
73-
* Testcase Example: '[2,3,-2,4]'
74-
*
75-
* Given an integer array nums, find the contiguous subarray within an array
76-
* (containing at least one number) which has the largest product.
77-
*
78-
* Example 1:
79-
*
80-
*
81-
* Input: [2,3,-2,4]
82-
* Output: 6
83-
* Explanation: [2,3] has the largest product 6.
84-
*
85-
*
86-
* Example 2:
87-
*
88-
*
89-
* Input: [-2,0,-1]
90-
* Output: 0
91-
* Explanation: The result cannot be 2, because [-2,-1] is not a subarray.
92-
*
93-
*/
94-
/**
95-
* @param {number[]} nums
96-
* @return {number}
97-
*/
98121
var maxProduct = function(nums) {
99122
let max = nums[0];
100123
let min = nums[0];
@@ -109,3 +132,8 @@ var maxProduct = function(nums) {
109132
return res;
110133
};
111134
```
135+
136+
137+
**复杂度分析**
138+
- 时间复杂度:$O(N)$
139+
- 空间复杂度:$O(1)$

problems/206.reverse-linked-list.md

Lines changed: 28 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -25,39 +25,11 @@ A linked list can be reversed either iteratively or recursively. Could you imple
2525

2626
## 代码
2727

28-
语言支持:JS, C++, Python
28+
语言支持:JS, C++, Python,Java
2929

3030
JavaScript Code:
3131

3232
```js
33-
/*
34-
* @lc app=leetcode id=206 lang=javascript
35-
*
36-
* [206] Reverse Linked List
37-
*
38-
* https://leetcode.com/problems/reverse-linked-list/description/
39-
*
40-
* algorithms
41-
* Easy (52.95%)
42-
* Total Accepted: 532.6K
43-
* Total Submissions: 1M
44-
* Testcase Example: '[1,2,3,4,5]'
45-
*
46-
* Reverse a singly linked list.
47-
*
48-
* Example:
49-
*
50-
*
51-
* Input: 1->2->3->4->5->NULL
52-
* Output: 5->4->3->2->1->NULL
53-
*
54-
*
55-
* Follow up:
56-
*
57-
* A linked list can be reversed either iteratively or recursively. Could you
58-
* implement both?
59-
*
60-
*/
6133
/**
6234
* Definition for singly-linked list.
6335
* function ListNode(val) {
@@ -134,6 +106,33 @@ class Solution:
134106
return prev
135107
```
136108

109+
Java Code:
110+
111+
```java
112+
/**
113+
* Definition for singly-linked list.
114+
* public class ListNode {
115+
* int val;
116+
* ListNode next;
117+
* ListNode(int x) { val = x; }
118+
* }
119+
*/
120+
class Solution {
121+
public ListNode reverseList(ListNode head) {
122+
ListNode pre = null, cur = head;
123+
124+
while (cur != null) {
125+
ListNode next = cur.next;
126+
cur.next = pre;
127+
pre = cur;
128+
cur = next;
129+
}
130+
131+
return pre;
132+
}
133+
}
134+
```
135+
137136
## 拓展
138137

139138
通过单链表的定义可以得知,单链表也是递归结构,因此,也可以使用递归的方式来进行reverse操作。

problems/322.coin-change.md

Lines changed: 56 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,37 @@ eg: 对于 [1,2,5] 组成 11 块
5555

5656
对于动态规划我们可以先画一个二维表,然后观察,其是否可以用一维表代替。
5757
关于动态规划为什么要画表,我已经在[这篇文章](../thinkings/dynamic-programming.md)解释了
58+
59+
比较容易想到的是二维数组:
60+
61+
```python
62+
class Solution:
63+
def coinChange(self, coins: List[int], amount: int) -> int:
64+
if amount < 0:
65+
return - 1
66+
dp = [[amount + 1 for _ in range(len(coins) + 1)]
67+
for _ in range(amount + 1)]
68+
# 初始化第一行为0,其他为最大值(也就是amount + 1)
69+
70+
for j in range(len(coins) + 1):
71+
dp[0][j] = 0
72+
73+
for i in range(1, amount + 1):
74+
for j in range(1, len(coins) + 1):
75+
if i - coins[j - 1] >= 0:
76+
dp[i][j] = min(
77+
dp[i][j - 1], dp[i - coins[j - 1]][j] + 1)
78+
else:
79+
dp[i][j] = dp[i][j - 1]
80+
81+
return -1 if dp[-1][-1] == amount + 1 else dp[-1][-1]
82+
```
83+
84+
**复杂度分析**
85+
- 时间复杂度:$O(amonut * len(coins))$
86+
- 空间复杂度:$O(amount * len(coins))$
87+
88+
dp[i][j] 依赖于` dp[i][j - 1]``dp[i - coins[j - 1]][j] + 1)` 这是一个优化的信号,我们可以将其优化到一维,具体见下方。
5889
## 关键点解析
5990

6091
- 动态规划
@@ -73,51 +104,11 @@ eg: 对于 [1,2,5] 组成 11 块
73104

74105
## 代码
75106

76-
* 语言支持:JS,C++
107+
108+
* 语言支持:JS,C++,Python3
77109

78110
JavaScript Code:
79111
```js
80-
/*
81-
* @lc app=leetcode id=322 lang=javascript
82-
*
83-
* [322] Coin Change
84-
*
85-
* https://leetcode.com/problems/coin-change/description/
86-
*
87-
* algorithms
88-
* Medium (29.25%)
89-
* Total Accepted: 175K
90-
* Total Submissions: 591.9K
91-
* Testcase Example: '[1,2,5]\n11'
92-
*
93-
* You are given coins of different denominations and a total amount of money
94-
* amount. Write a function to compute the fewest number of coins that you need
95-
* to make up that amount. If that amount of money cannot be made up by any
96-
* combination of the coins, return -1.
97-
*
98-
* Example 1:
99-
*
100-
*
101-
* Input: coins = [1, 2, 5], amount = 11
102-
* Output: 3
103-
* Explanation: 11 = 5 + 5 + 1
104-
*
105-
* Example 2:
106-
*
107-
*
108-
* Input: coins = [2], amount = 3
109-
* Output: -1
110-
*
111-
*
112-
* Note:
113-
* You may assume that you have an infinite number of each kind of coin.
114-
*
115-
*/
116-
/**
117-
* @param {number[]} coins
118-
* @param {number} amount
119-
* @return {number}
120-
*/
121112

122113
var coinChange = function(coins, amount) {
123114
if (amount === 0) {
@@ -157,10 +148,32 @@ public:
157148
}
158149
};
159150
```
151+
152+
Python3 Code:
153+
154+
```python
155+
class Solution:
156+
def coinChange(self, coins: List[int], amount: int) -> int:
157+
dp = [amount + 1] * (amount + 1)
158+
dp[0] = 0
159+
160+
for i in range(1, amount + 1):
161+
for j in range(len(coins)):
162+
if i >= coins[j]:
163+
dp[i] = min(dp[i], dp[i - coins[j]] + 1)
164+
165+
return -1 if dp[-1] == amount + 1 else dp[-1]
166+
```
167+
168+
**复杂度分析**
169+
- 时间复杂度:$O(amonut * len(coins))$
170+
- 空间复杂度:$O(amount)$
171+
172+
160173
## 扩展
161174

162175
这是一道很简单描述的题目, 因此很多时候会被用到大公司的电面中。
163176

164177
相似问题:
165178

166-
[518.coin-change-2](./518.coin-change-2.md)
179+
[518.coin-change-2](https://github.com/azl397985856/leetcode/blob/master/problems/518.coin-change-2.md)

0 commit comments

Comments
 (0)