Skip to content

Commit 27ddab1

Browse files
authored
feat: add solutions to lc problem: No.2369 (#2380)
No.2369.Check if There is a Valid Partition For The Array
1 parent 90877bf commit 27ddab1

File tree

12 files changed

+356
-424
lines changed

12 files changed

+356
-424
lines changed

solution/2300-2399/2369.Check if There is a Valid Partition For The Array/README.md

+126-148
Original file line numberDiff line numberDiff line change
@@ -52,31 +52,49 @@
5252

5353
### 方法一:记忆化搜索
5454

55-
$dfs(i)$ 表示从数组从下标 $i$ 开始到结尾,是否至少存在一个有效的划分
55+
我们设计一个函数 $dfs(i)$,表示从下标 $i$ 开始是否存在一种有效划分。那么答案就是 $dfs(0)$
5656

57-
时间复杂度 $O(n)$,空间复杂度 $O(n)$。
57+
函数 $dfs(i)$ 的执行过程如下:
58+
59+
- 如果 $i \ge n$,返回 $true$。
60+
- 如果 $i$ 和 $i+1$ 下标的元素相等,那么可以选择将 $i$ 和 $i+1$ 作为一个子数组,递归调用 $dfs(i+2)$。
61+
- 如果 $i$, $i+1$ 和 $i+2$ 下标的元素相等,那么可以选择将 $i$, $i+1$ 和 $i+2$ 作为一个子数组,递归调用 $dfs(i+3)$。
62+
- 如果 $i$, $i+1$ 和 $i+2$ 下标的元素依次递增 $1$,那么可以选择将 $i$, $i+1$ 和 $i+2$ 作为一个子数组,递归调用 $dfs(i+3)$。
63+
- 如果上述情况都不满足,返回 $false$,否则返回 $true$。
64+
65+
即:
66+
67+
$$
68+
dfs(i) = \text{OR}
69+
\begin{cases}
70+
true,&i \ge n\\
71+
dfs(i+2),&i+1 < n\ \text{and}\ \textit{nums}[i] = \textit{nums}[i+1]\\
72+
dfs(i+3),&i+2 < n\ \text{and}\ \textit{nums}[i] = \textit{nums}[i+1] = \textit{nums}[i+2]\\
73+
dfs(i+3),&i+2 < n\ \text{and}\ \textit{nums}[i+1] - \textit{nums}[i] = 1\ \text{and}\ \textit{nums}[i+2] - \textit{nums}[i+1] = 1
74+
\end{cases}
75+
$$
76+
77+
为了避免重复计算,我们使用记忆化搜索的方法。
78+
79+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组的长度。
5880

5981
<!-- tabs:start -->
6082

6183
```python
6284
class Solution:
6385
def validPartition(self, nums: List[int]) -> bool:
6486
@cache
65-
def dfs(i):
66-
if i == n:
87+
def dfs(i: int) -> bool:
88+
if i >= n:
6789
return True
68-
res = False
69-
if i < n - 1 and nums[i] == nums[i + 1]:
70-
res = res or dfs(i + 2)
71-
if i < n - 2 and nums[i] == nums[i + 1] and nums[i + 1] == nums[i + 2]:
72-
res = res or dfs(i + 3)
73-
if (
74-
i < n - 2
90+
a = i + 1 < n and nums[i] == nums[i + 1]
91+
b = i + 2 < n and nums[i] == nums[i + 1] == nums[i + 2]
92+
c = (
93+
i + 2 < n
7594
and nums[i + 1] - nums[i] == 1
7695
and nums[i + 2] - nums[i + 1] == 1
77-
):
78-
res = res or dfs(i + 3)
79-
return res
96+
)
97+
return (a and dfs(i + 2)) or ((b or c) and dfs(i + 3))
8098

8199
n = len(nums)
82100
return dfs(0)
@@ -85,63 +103,58 @@ class Solution:
85103
```java
86104
class Solution {
87105
private int n;
88-
private int[] f;
89106
private int[] nums;
107+
private Boolean[] f;
90108

91109
public boolean validPartition(int[] nums) {
92-
this.nums = nums;
93110
n = nums.length;
94-
f = new int[n];
95-
Arrays.fill(f, -1);
111+
this.nums = nums;
112+
f = new Boolean[n];
96113
return dfs(0);
97114
}
98115

99116
private boolean dfs(int i) {
100-
if (i == n) {
117+
if (i >= n) {
101118
return true;
102119
}
103-
if (f[i] != -1) {
104-
return f[i] == 1;
105-
}
106-
boolean res = false;
107-
if (i < n - 1 && nums[i] == nums[i + 1]) {
108-
res = res || dfs(i + 2);
109-
}
110-
if (i < n - 2 && nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) {
111-
res = res || dfs(i + 3);
120+
if (f[i] != null) {
121+
return f[i];
112122
}
113-
if (i < n - 2 && nums[i + 1] - nums[i] == 1 && nums[i + 2] - nums[i + 1] == 1) {
114-
res = res || dfs(i + 3);
115-
}
116-
f[i] = res ? 1 : 0;
117-
return res;
123+
boolean a = i + 1 < n && nums[i] == nums[i + 1];
124+
boolean b = i + 2 < n && nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2];
125+
boolean c = i + 2 < n && nums[i + 1] - nums[i] == 1 && nums[i + 2] - nums[i + 1] == 1;
126+
return f[i] = ((a && dfs(i + 2)) || ((b || c) && dfs(i + 3)));
118127
}
119128
}
120129
```
121130

122131
```cpp
123132
class Solution {
124133
public:
125-
vector<int> f;
126-
vector<int> nums;
127-
int n;
128-
129134
bool validPartition(vector<int>& nums) {
130135
n = nums.size();
131136
this->nums = nums;
132137
f.assign(n, -1);
133138
return dfs(0);
134139
}
135140

141+
private:
142+
int n;
143+
vector<int> f;
144+
vector<int> nums;
145+
136146
bool dfs(int i) {
137-
if (i == n) return true;
138-
if (f[i] != -1) return f[i] == 1;
139-
bool res = false;
140-
if (i < n - 1 && nums[i] == nums[i + 1]) res = res || dfs(i + 2);
141-
if (i < n - 2 && nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) res = res || dfs(i + 3);
142-
if (i < n - 2 && nums[i + 1] - nums[i] == 1 && nums[i + 2] - nums[i + 1] == 1) res = res || dfs(i + 3);
143-
f[i] = res ? 1 : 0;
144-
return res;
147+
if (i >= n) {
148+
return true;
149+
}
150+
if (f[i] != -1) {
151+
return f[i] == 1;
152+
}
153+
bool a = i + 1 < n && nums[i] == nums[i + 1];
154+
bool b = i + 2 < n && nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2];
155+
bool c = i + 2 < n && nums[i + 1] - nums[i] == 1 && nums[i + 2] - nums[i + 1] == 1;
156+
f[i] = ((a && dfs(i + 2)) || ((b || c) && dfs(i + 3))) ? 1 : 0;
157+
return f[i] == 1;
145158
}
146159
};
147160
```
@@ -161,21 +174,14 @@ func validPartition(nums []int) bool {
161174
if f[i] != -1 {
162175
return f[i] == 1
163176
}
164-
res := false
177+
a := i+1 < n && nums[i] == nums[i+1]
178+
b := i+2 < n && nums[i] == nums[i+1] && nums[i+1] == nums[i+2]
179+
c := i+2 < n && nums[i+1]-nums[i] == 1 && nums[i+2]-nums[i+1] == 1
165180
f[i] = 0
166-
if i < n-1 && nums[i] == nums[i+1] {
167-
res = res || dfs(i+2)
168-
}
169-
if i < n-2 && nums[i] == nums[i+1] && nums[i+1] == nums[i+2] {
170-
res = res || dfs(i+3)
171-
}
172-
if i < n-2 && nums[i+1]-nums[i] == 1 && nums[i+2]-nums[i+1] == 1 {
173-
res = res || dfs(i+3)
174-
}
175-
if res {
181+
if a && dfs(i+2) || b && dfs(i+3) || c && dfs(i+3) {
176182
f[i] = 1
177183
}
178-
return res
184+
return f[i] == 1
179185
}
180186
return dfs(0)
181187
}
@@ -184,95 +190,75 @@ func validPartition(nums []int) bool {
184190
```ts
185191
function validPartition(nums: number[]): boolean {
186192
const n = nums.length;
187-
const vis = new Array(n).fill(false);
188-
const queue = [0];
189-
while (queue.length !== 0) {
190-
const i = queue.shift() ?? 0;
191-
192-
if (i === n) {
193+
const f: number[] = Array(n).fill(-1);
194+
const dfs = (i: number): boolean => {
195+
if (i >= n) {
193196
return true;
194197
}
195-
196-
if (!vis[i + 2] && i + 2 <= n && nums[i] === nums[i + 1]) {
197-
queue.push(i + 2);
198-
vis[i + 2] = true;
199-
}
200-
201-
if (
202-
!vis[i + 3] &&
203-
i + 3 <= n &&
204-
((nums[i] === nums[i + 1] && nums[i + 1] === nums[i + 2]) ||
205-
(nums[i] === nums[i + 1] - 1 && nums[i + 1] === nums[i + 2] - 1))
206-
) {
207-
queue.push(i + 3);
208-
vis[i + 3] = true;
198+
if (f[i] !== -1) {
199+
return f[i] === 1;
209200
}
210-
}
211-
return false;
201+
const a = i + 1 < n && nums[i] == nums[i + 1];
202+
const b = i + 2 < n && nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2];
203+
const c = i + 2 < n && nums[i + 1] - nums[i] == 1 && nums[i + 2] - nums[i + 1] == 1;
204+
f[i] = (a && dfs(i + 2)) || ((b || c) && dfs(i + 3)) ? 1 : 0;
205+
return f[i] == 1;
206+
};
207+
return dfs(0);
212208
}
213209
```
214210

215211
<!-- tabs:end -->
216212

217213
### 方法二:动态规划
218214

219-
设 $dp[i]$ 表示数组前 $i$ 个元素是否至少存在一个有效的划分。初始时 $dp[0]=true$, $dp[1]=false$
215+
我们可以将方法一中的记忆化搜索转换为动态规划
220216

221-
根据题意,当 $i \ge 2$ 时,有
217+
设 $f[i]$ 表示数组的前 $i$ 个元素是否存在一种有效划分,初始时 $f[0] = true$,答案就是 $f[n]$。
218+
219+
状态转移方程如下:
222220

223221
$$
224-
dp[i] = \text{OR}
222+
f[i] = \text{OR}
225223
\begin{cases}
226-
dp[i-2]\ \text{AND}\ \textit{nums}[i-1] = \textit{nums}[i-2],&i>1\\
227-
dp[i-3]\ \text{AND}\ \textit{nums}[i-1] = \textit{nums}[i-2] = \textit{nums}[i-3],&i>2\\
228-
dp[i-3]\ \text{AND}\ \textit{nums}[i-1] = \textit{nums}[i-2]+1 = \textit{nums}[i-3]+2,&i>2
224+
true,&i = 0\\
225+
f[i-2],&i-2 \ge 0\ \text{and}\ \textit{nums}[i-1] = \textit{nums}[i-2]\\
226+
f[i-3],&i-3 \ge 0\ \text{and}\ \textit{nums}[i-1] = \textit{nums}[i-2] = \textit{nums}[i-3]\\
227+
f[i-3],&i-3 \ge 0\ \text{and}\ \textit{nums}[i-1] - \textit{nums}[i-2] = 1\ \text{and}\ \textit{nums}[i-2] - \textit{nums}[i-3] = 1
229228
\end{cases}
230229
$$
231230

232-
答案为 $dp[n]$。
233-
234-
时间复杂度 $O(n)$,空间复杂度 $O(n)$。
231+
时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组的长度。
235232

236233
<!-- tabs:start -->
237234

238235
```python
239236
class Solution:
240237
def validPartition(self, nums: List[int]) -> bool:
241238
n = len(nums)
242-
dp = [False] * (n + 1)
243-
dp[0] = True
244-
for i in range(2, n + 1):
245-
if nums[i - 1] == nums[i - 2]:
246-
dp[i] = dp[i] or dp[i - 2]
247-
if i > 2 and nums[i - 1] == nums[i - 2] == nums[i - 3]:
248-
dp[i] = dp[i] or dp[i - 3]
249-
if (
250-
i > 2
251-
and nums[i - 1] - nums[i - 2] == 1
252-
and nums[i - 2] - nums[i - 3] == 1
253-
):
254-
dp[i] = dp[i] or dp[i - 3]
255-
return dp[-1]
239+
f = [True] + [False] * n
240+
for i, x in enumerate(nums, 1):
241+
a = i - 2 >= 0 and nums[i - 2] == x
242+
b = i - 3 >= 0 and nums[i - 3] == nums[i - 2] == x
243+
c = i - 3 >= 0 and x - nums[i - 2] == 1 and nums[i - 2] - nums[i - 3] == 1
244+
f[i] = (a and f[i - 2]) or ((b or c) and f[i - 3])
245+
return f[n]
256246
```
257247

258248
```java
259249
class Solution {
260250
public boolean validPartition(int[] nums) {
261251
int n = nums.length;
262-
boolean[] dp = new boolean[n + 1];
263-
dp[0] = true;
264-
for (int i = 2; i <= n; ++i) {
265-
if (nums[i - 1] == nums[i - 2]) {
266-
dp[i] = dp[i] || dp[i - 2];
267-
}
268-
if (i > 2 && nums[i - 1] == nums[i - 2] && nums[i - 2] == nums[i - 3]) {
269-
dp[i] = dp[i] || dp[i - 3];
270-
}
271-
if (i > 2 && nums[i - 1] - nums[i - 2] == 1 && nums[i - 2] - nums[i - 3] == 1) {
272-
dp[i] = dp[i] || dp[i - 3];
273-
}
252+
boolean[] f = new boolean[n + 1];
253+
f[0] = true;
254+
for (int i = 1; i <= n; ++i) {
255+
boolean a = i - 2 >= 0 && nums[i - 1] == nums[i - 2];
256+
boolean b = i - 3 >= 0 && nums[i - 1] == nums[i - 2] && nums[i - 2] == nums[i - 3];
257+
boolean c
258+
= i - 3 >= 0 && nums[i - 1] - nums[i - 2] == 1 && nums[i - 2] - nums[i - 3] == 1;
259+
f[i] = (a && f[i - 2]) || ((b || c) && f[i - 3]);
274260
}
275-
return dp[n];
261+
return f[n];
276262
}
277263
}
278264
```
@@ -282,55 +268,47 @@ class Solution {
282268
public:
283269
bool validPartition(vector<int>& nums) {
284270
int n = nums.size();
285-
vector<bool> dp(n + 1);
286-
dp[0] = true;
287-
for (int i = 2; i <= n; ++i) {
288-
if (nums[i - 1] == nums[i - 2]) dp[i] = dp[i] || dp[i - 2];
289-
if (i > 2 && nums[i - 1] == nums[i - 2] && nums[i - 2] == nums[i - 3]) dp[i] = dp[i] || dp[i - 3];
290-
if (i > 2 && nums[i - 1] - nums[i - 2] == 1 && nums[i - 2] - nums[i - 3] == 1) dp[i] = dp[i] || dp[i - 3];
271+
vector<bool> f(n + 1);
272+
f[0] = true;
273+
for (int i = 1; i <= n; ++i) {
274+
bool a = i - 2 >= 0 && nums[i - 1] == nums[i - 2];
275+
bool b = i - 3 >= 0 && nums[i - 1] == nums[i - 2] && nums[i - 2] == nums[i - 3];
276+
bool c = i - 3 >= 0 && nums[i - 1] - nums[i - 2] == 1 && nums[i - 2] - nums[i - 3] == 1;
277+
f[i] = (a && f[i - 2]) || ((b || c) && f[i - 3]);
291278
}
292-
return dp[n];
279+
return f[n];
293280
}
294281
};
295282
```
296283
297284
```go
298285
func validPartition(nums []int) bool {
299286
n := len(nums)
300-
dp := make([]bool, n+1)
301-
dp[0] = true
302-
for i := 2; i <= n; i++ {
303-
if nums[i-1] == nums[i-2] {
304-
dp[i] = dp[i] || dp[i-2]
305-
}
306-
if i > 2 && nums[i-1] == nums[i-2] && nums[i-2] == nums[i-3] {
307-
dp[i] = dp[i] || dp[i-3]
308-
}
309-
if i > 2 && nums[i-1]-nums[i-2] == 1 && nums[i-2]-nums[i-3] == 1 {
310-
dp[i] = dp[i] || dp[i-3]
311-
}
287+
f := make([]bool, n+1)
288+
f[0] = true
289+
for i := 1; i <= n; i++ {
290+
x := nums[i-1]
291+
a := i-2 >= 0 && nums[i-2] == x
292+
b := i-3 >= 0 && nums[i-3] == nums[i-2] && nums[i-2] == x
293+
c := i-3 >= 0 && x-nums[i-2] == 1 && nums[i-2]-nums[i-3] == 1
294+
f[i] = (a && f[i-2]) || ((b || c) && f[i-3])
312295
}
313-
return dp[n]
296+
return f[n]
314297
}
315298
```
316299

317300
```ts
318301
function validPartition(nums: number[]): boolean {
319302
const n = nums.length;
320-
const dp = new Array(n + 1).fill(false);
321-
dp[0] = true;
322-
for (let i = 2; i <= n; ++i) {
323-
if (nums[i - 1] == nums[i - 2]) {
324-
dp[i] = dp[i] || dp[i - 2];
325-
}
326-
if (i > 2 && nums[i - 1] == nums[i - 2] && nums[i - 2] == nums[i - 3]) {
327-
dp[i] = dp[i] || dp[i - 3];
328-
}
329-
if (i > 2 && nums[i - 1] - nums[i - 2] == 1 && nums[i - 2] - nums[i - 3] == 1) {
330-
dp[i] = dp[i] || dp[i - 3];
331-
}
303+
const f: boolean[] = Array(n + 1).fill(false);
304+
f[0] = true;
305+
for (let i = 1; i <= n; ++i) {
306+
const a = i - 2 >= 0 && nums[i - 1] === nums[i - 2];
307+
const b = i - 3 >= 0 && nums[i - 1] === nums[i - 2] && nums[i - 2] === nums[i - 3];
308+
const c = i - 3 >= 0 && nums[i - 1] - nums[i - 2] === 1 && nums[i - 2] - nums[i - 3] === 1;
309+
f[i] = (a && f[i - 2]) || ((b || c) && f[i - 3]);
332310
}
333-
return dp[n];
311+
return f[n];
334312
}
335313
```
336314

0 commit comments

Comments
 (0)