Skip to content

Commit 300dd2d

Browse files
committed
✨update: Modify 978
1 parent 218f62a commit 300dd2d

File tree

3 files changed

+52
-67
lines changed

3 files changed

+52
-67
lines changed

Index/线性 DP.md

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
| [650. 只有两个键的键盘](https://leetcode-cn.com/problems/2-keys-keyboard/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/2-keys-keyboard/solution/gong-shui-san-xie-yi-ti-san-jie-dong-tai-f035/) | 中等 | 🤩🤩🤩🤩 |
1515
| [678. 有效的括号字符串](https://leetcode-cn.com/problems/valid-parenthesis-string/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/valid-parenthesis-string/solution/gong-shui-san-xie-yi-ti-shuang-jie-dong-801rq/) | 中等 | 🤩🤩🤩🤩🤩 |
1616
| [688. 骑士在棋盘上的概率](https://leetcode-cn.com/problems/knight-probability-in-chessboard/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/knight-probability-in-chessboard/solution/gong-shui-san-xie-jian-dan-qu-jian-dp-yu-st8l/) | 中等 | 🤩🤩🤩🤩🤩 |
17+
| [978. 最长湍流子数组](https://leetcode-cn.com/problems/longest-turbulent-subarray/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/longest-turbulent-subarray/solution/xiang-jie-dong-tai-gui-hua-ru-he-cai-dp-3spgj/) | 中等 | 🤩🤩🤩🤩 |
1718
| [1137. 第 N 个泰波那契数](https://leetcode-cn.com/problems/n-th-tribonacci-number/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/n-th-tribonacci-number/solution/gong-shui-san-xie-yi-ti-si-jie-die-dai-d-m1ie/) | 简单 | 🤩🤩🤩🤩 |
1819
| [1220. 统计元音字母序列的数目](https://leetcode-cn.com/problems/count-vowels-permutation/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/count-vowels-permutation/solution/gong-shui-san-xie-yi-ti-shuang-jie-xian-n8f4o/) | 困难 | 🤩🤩🤩🤩 |
1920
| [1751. 最多可以参加的会议数目 II](https://leetcode-cn.com/problems/maximum-number-of-events-that-can-be-attended-ii/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/maximum-number-of-events-that-can-be-attended-ii/solution/po-su-dp-er-fen-dp-jie-fa-by-ac_oier-88du/) | 困难 | 🤩🤩🤩 |

Index/背包 DP.md

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@
22
| ------------------------------------------------------------ | ------------------------------------------------------------ | ---- | ----- |
33
| [279. 完全平方数](https://leetcode-cn.com/problems/perfect-squares/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/perfect-squares/solution/gong-shui-san-xie-xiang-jie-wan-quan-bei-nqes/) | 中等 | 🤩🤩🤩🤩 |
44
| [322. 零钱兑换](https://leetcode-cn.com/problems/coin-change/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/coin-change/solution/dong-tai-gui-hua-bei-bao-wen-ti-zhan-zai-3265/) | 中等 | 🤩🤩🤩🤩 |
5-
| [416. 分割等和子集](https://leetcode-cn.com/problems/partition-equal-subset-sum/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/gong-shui-san-xie-bei-bao-wen-ti-xia-con-mr8a/) | 中等 | 🤩🤩🤩🤩🤩 |
5+
| [416. 分割等和子集](https://leetcode-cn.com/problems/partition-equal-subset-sum/) | [[] LeetCode 题解链接](https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/gong-shui-san-xie-bei-bao-wen-ti-shang-r-ln14/) | 中等 | 🤩🤩🤩🤩🤩 |
6+
| [416. 分割等和子集](https://leetcode-cn.com/problems/partition-equal-subset-sum/) | [[] LeetCode 题解链接](https://leetcode-cn.com/problems/partition-equal-subset-sum/solution/gong-shui-san-xie-bei-bao-wen-ti-xia-con-mr8a/) | 中等 | 🤩🤩🤩🤩🤩 |
67
| [474. 一和零](https://leetcode-cn.com/problems/ones-and-zeroes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/ones-and-zeroes/solution/gong-shui-san-xie-xiang-jie-ru-he-zhuan-174wv/) | 中等 | 🤩🤩🤩🤩🤩 |
78
| [494. 目标和](https://leetcode-cn.com/problems/target-sum/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/target-sum/solution/gong-shui-san-xie-yi-ti-si-jie-dfs-ji-yi-et5b/) | 中等 | 🤩🤩🤩🤩 |
89
| [518. 零钱兑换 II](https://leetcode-cn.com/problems/coin-change-2/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/coin-change-2/solution/gong-shui-san-xie-xiang-jie-wan-quan-bei-6hxv/) | 中等 | 🤩🤩🤩🤩 |

LeetCode/971-980/978. 最长湍流子数组(中等).md

+49-66
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,18 @@
22

33
这是 LeetCode 上的 **[978. 最长湍流子数组](https://leetcode-cn.com/problems/longest-turbulent-subarray/solution/xiang-jie-dong-tai-gui-hua-ru-he-cai-dp-3spgj/)** ,难度为 **中等**
44

5-
Tag : 「序列 DP」
5+
Tag : 「线性 DP」、「序列 DP」
66

77

88

9-
A 的子数组 A[i], A[i+1], ..., A[j] 满足下列条件时,我们称其为湍流子数组:
9+
`A` 的子数组 $A[i], A[i+1], ..., A[j]$ 满足下列条件时,我们称其为湍流子数组:
1010

11-
* 若 i <= k < j,当 k 为奇数时, A[k] > A[k+1],且当 k 为偶数时,A[k] < A[k+1]
12-
* 或 若 i <= k < j,当 k 为偶数时,A[k] > A[k+1] ,且当 k 为奇数时, A[k] < A[k+1]
11+
* 若 $i <= k < j$,当 $k$ 为奇数时,$A[k] > A[k+1]$,且当 $k$ 为偶数时,$A[k] < A[k+1]$
12+
* 若 $i <= k < j$,当 $k$ 为偶数时,$A[k] > A[k+1]$ ,且当 $k$ 为奇数时,$A[k] < A[k+1]$
1313

1414
也就是说,如果比较符号在子数组中的每个相邻元素对之间翻转,则该子数组是湍流子数组。
1515

16-
返回 A 的最大湍流子数组的长度。
16+
返回 `A` 的最大湍流子数组的长度。
1717

1818
示例 1:
1919
```
@@ -33,58 +33,55 @@ Tag : 「序列 DP」
3333
```
3434

3535
提示:
36-
* 1 <= A.length <= 40000
37-
* 0 <= A[i] <= $10^9$
36+
* $1 <= A.length <= 40000$
37+
* $0 <= A[i] <= 10^9$
3838

3939
---
4040

41-
### 基本分析思路
41+
### 基本思路
4242

4343
本题其实是要我们求最长一段呈 `↗ ↘ ↗ ↘` 或者 `↘ ↗ ↘ ↗` 形状的数组长度。
4444

45-
看一眼数据范围,有 40000,那么枚举起点和终点,然后对划分出来的子数组检查是否为「湍流子数组」的朴素解法就不能过了。
45+
看一眼数据范围,有 $40000$,那么枚举起点和终点,然后对划分出来的子数组检查是否为「湍流子数组」的朴素解法就不能过了。
4646

4747
朴素解法的复杂度为 $O(n^3)$ ,直接放弃朴素解法。
4848

4949
复杂度往下优化,其实就 $O(n)$ 的 DP 解法了。
5050

51-
***
51+
---
5252

5353
### 动态规划
5454

55-
至于 DP 如何分析,通过我们会先考虑一维 DP 能否求解,不行再考虑二维 DP ...
55+
至于 DP 如何分析,通过我们会先考虑一维 DP 能否求解,不行再考虑二维 DP
5656

5757
对于本题,**由于每个位置而言,能否「接着」上一个位置**形成「湍流」,取决于上一位置是由什么形状而来。
5858

5959
举个例子,对于样例 `[3,4,2]`,从 4 -> 2 已经确定是 `` 状态,那么对于 2 这个位置能否「接着」4 形成「湍流」,要求 4 必须是由 `` 而来。
6060

6161
**因此我们还需要记录某一位是如何来的(`` 还是 ``),需要使二维 DP 来求解 ~**
6262

63-
我们定义 f(i,j) 代表以位置 i 为结尾,而结尾状态为 j 的最长湍流子数组长度(0:上升状态 / 1:下降状态)
64-
65-
*PS. 这里的状态定义我是猜的,这其实是个技巧。通常我们做 DP 题,都是先猜一个定义,然后看看这个定义是否能分析出状态转移方程帮助我们「不重不漏」的枚举所有的方案。一般我是直接根据答案来猜定义,这里是求最长子数组长度,所以我猜一个 f(i,j) 代表最长湍流子数组长度*
63+
我们定义 $f[i][j]$ 代表以位置 $i$ 为结尾,而结尾状态为 $j$ 的最长湍流子数组长度(0:上升状态 / 1:下降状态)
6664

67-
那么 `f[i][j]` 该如何求解呢?
65+
> PS. 这里的状态定义我是猜的,这其实是个技巧。通常我们做 DP 题,都是先猜一个定义,然后看看这个定义是否能分析出状态转移方程帮助我们「不重不漏」的枚举所有的方案。一般我是直接根据答案来猜定义,这里是求最长子数组长度,所以我猜一个 f(i,j) 代表最长湍流子数组长度
6866
69-
我们知道位置 `i` 是如何来是唯一确定的(取决于 `arr[i]``arr[i - 1]` 的大小关系),而只有三种可能性:
67+
不失一般性考虑 $f[i][j]$ 该如何求解,我们知道位置 $i$ 是如何来是唯一确定的(取决于 $arr[i]$$arr[i - 1]$ 的大小关系),而只有三种可能性:
7068

71-
* `arr[i - 1] < arr[i]`:该点是由上升而来,能够「接着」的条件是 `i - 1` 是由下降而来。则有:`f[i][0] = f[i - 1][1] + 1`
72-
* `arr[i - 1] > arr[i]`:改点是由下降而来,能够「接着」的条件是 `i - 1` 是由上升而来。则有:`f[i][1] = f[i - 1][0] + 1`
73-
* `arr[i - 1] = arr[i]`:不考虑,不符合「湍流」的定义
69+
* $arr[i - 1] < arr[i]$:该点是由上升而来,能够「接着」的条件是 $i - 1$ 是由下降而来。则有:$f[i][0] = f[i - 1][1] + 1$
70+
* $arr[i - 1] > arr[i]$:改点是由下降而来,能够「接着」的条件是 $i - 1$ 是由上升而来。则有:$f[i][1] = f[i - 1][0] + 1$
71+
* $arr[i - 1] = arr[i]$:不考虑,不符合「湍流」的定义
7472

7573
代码:
76-
```java
74+
```Java
7775
class Solution {
7876
public int maxTurbulenceSize(int[] arr) {
79-
int n = arr.length;
80-
int ans = 1;
77+
int n = arr.length, ans = 1;
8178
int[][] f = new int[n][2];
82-
for (int i = 0; i < 2; i++) f[0][i] = 1;
79+
f[0][0] = f[0][1] = 1;
8380
for (int i = 1; i < n; i++) {
84-
for (int j = 0; j < 2; j++) f[i][j] = 1;
85-
if (arr[i - 1] < arr[i]) f[i][0] = f[i - 1][1] + 1;
86-
if (arr[i - 1] > arr[i]) f[i][1] = f[i - 1][0] + 1;
87-
for (int j = 0; j < 2; j++) ans = Math.max(ans, f[i][j]);
81+
f[i][0] = f[i][1] = 1;
82+
if (arr[i] > arr[i - 1]) f[i][0] = f[i - 1][1] + 1;
83+
else if (arr[i] < arr[i - 1]) f[i][1] = f[i - 1][0] + 1;
84+
ans = Math.max(ans, Math.max(f[i][0], f[i][1]));
8885
}
8986
return ans;
9087
}
@@ -93,28 +90,28 @@ class Solution {
9390
* 时间复杂度:$O(n)$
9491
* 空间复杂度:$O(n)$
9592

96-
***
93+
---
9794

98-
### 动态规划(空间优化:奇偶滚动
95+
### 空间优化:奇偶滚动
9996

100-
我们发现对于 `f[i][j]` 状态的更新只依赖于 `f[i - 1][j]` 的状态。
97+
我们发现对于 $f[i][j]$ 状态的更新只依赖于 $f[i - 1][j]$ 的状态。
10198

102-
因此我们可以使用「奇偶滚动」方式来将第一维从 `n` 优化到 2
99+
因此我们可以使用「奇偶滚动」方式来将第一维从 $n$ 优化到 $2$
103100

104-
修改的方式也十分机械,只需要改为「奇偶滚动」的维度直接修改成 2 ,然后该维度的所有访问方式增加 `%2` 即可:
101+
修改的方式也十分机械,只需要改为「奇偶滚动」的维度直接修改成 $2$ ,然后该维度的所有访问方式增加 `%2` 或者 `&1` 即可:
105102

106-
```java
103+
代码:
104+
```Java
107105
class Solution {
108106
public int maxTurbulenceSize(int[] arr) {
109-
int n = arr.length;
110-
int ans = 1;
107+
int n = arr.length, ans = 1;
111108
int[][] f = new int[2][2];
112-
for (int i = 0; i < 2; i++) f[0][i] = 1;
109+
f[0][0] = f[0][1] = 1;
113110
for (int i = 1; i < n; i++) {
114-
for (int j = 0; j < 2; j++) f[i % 2][j] = 1;
115-
if (arr[i - 1] < arr[i]) f[i % 2][0] = f[(i - 1) % 2][1] + 1;
116-
if (arr[i - 1] > arr[i]) f[i % 2][1] = f[(i - 1) % 2][0] + 1;
117-
for (int j = 0; j < 2; j++) ans = Math.max(ans, f[i % 2][j]);
111+
f[i % 2][0] = f[i % 2][1] = 1;
112+
if (arr[i] > arr[i - 1]) f[i % 2][0] = f[(i - 1) % 2][1] + 1;
113+
else if (arr[i] < arr[i - 1]) f[i % 2][1] = f[(i - 1) % 2][0] + 1;
114+
ans = Math.max(ans, Math.max(f[i % 2][0], f[i % 2][1]));
118115
}
119116
return ans;
120117
}
@@ -123,38 +120,30 @@ class Solution {
123120
* 时间复杂度:$O(n)$
124121
* 空间复杂度:使用固定 `2 * 2` 的数组空间。复杂度为 $O(1)$
125122

126-
***
123+
---
127124

128-
### 动态规划(空间优化:维度消除
125+
### 空间优化:维度消除
129126

130127
既然只需要记录上一行状态,能否直接将行的维度消除呢?
131128

132-
答案是可以的,当我们要转移第 `i` 行的时候,`f` 数组装的就已经是 `i - 1` 行的结果。
129+
答案是可以的,当我们要转移第 $i$ 行的时候,$f[i]$ 装的就已经是 $i - 1$ 行的结果。
133130

134131
这也是著名「背包问题」的一维通用优手段。
135132

136133
但相比于「奇偶滚动」的空间优化,这种优化手段只是常数级别的优化(空间复杂度与「奇偶滚动」相同),而且优化通常涉及代码改动。
137134

138-
```java
135+
代码:
136+
```Java
139137
class Solution {
140138
public int maxTurbulenceSize(int[] arr) {
141-
int n = arr.length;
142-
int ans = 1;
139+
int n = arr.length, ans = 1;
143140
int[] f = new int[2];
144-
for (int i = 0; i < 2; i++) f[i] = 1;
141+
f[0] = f[1] = 1;
145142
for (int i = 1; i < n; i++) {
146-
int dp0 = f[0], dp1 = f[1];
147-
if (arr[i - 1] < arr[i]) {
148-
f[0] = dp1 + 1;
149-
} else {
150-
f[0] = 1;
151-
}
152-
if (arr[i - 1] > arr[i]) {
153-
f[1] = dp0 + 1;
154-
} else {
155-
f[1] = 1;
156-
}
157-
for (int j = 0; j < 2; j++) ans = Math.max(ans, f[j]);
143+
int a = f[0], b = f[1];
144+
f[0] = arr[i - 1] < arr[i] ? b + 1 : 1;
145+
f[1] = arr[i - 1] > arr[i] ? a + 1 : 1;
146+
ans = Math.max(ans, Math.max(f[0], f[1]));
158147
}
159148
return ans;
160149
}
@@ -163,17 +152,11 @@ class Solution {
163152
* 时间复杂度:$O(n)$
164153
* 空间复杂度:$O(1)$
165154

166-
***
167-
168-
### 其他
169-
170-
如果你对「猜 DP 的状态定义」还没感觉,这里有道类似的题目可以瞧一眼:[45. 跳跃游戏 II](https://leetcode-cn.com/problems/jump-game-ii/solution/xiang-jie-dp-tan-xin-shuang-zhi-zhen-jie-roh4/)
171-
172155
---
173156

174157
### 最后
175158

176-
这是我们「刷穿 LeetCode」系列文章的第 `No.978` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完
159+
这是我们「刷穿 LeetCode」系列文章的第 `No.978` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完
177160

178161
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
179162

0 commit comments

Comments
 (0)