Skip to content

Commit bb69d6e

Browse files
Merge pull request SharingSource#791 from SharingSource/ac_oier
🌟 feat: add 10、1004、1006、1038、1052、115、119、1190、1206、1208、1233、1282、1…
2 parents a4120c8 + c1a446b commit bb69d6e

File tree

117 files changed

+7969
-1361
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+7969
-1361
lines changed

LeetCode/1-10/10. 正则表达式匹配(困难).md

+71-23
Original file line numberDiff line numberDiff line change
@@ -74,41 +74,28 @@ Tag : 「动态规划」、「序列 DP」
7474
本题可以使用动态规划进行求解:
7575

7676
* 状态定义:`f(i,j)` 代表考虑 `s` 中以 `i` 为结尾的子串和 `p` 中的 `j` 为结尾的子串是否匹配。最终我们要求的结果为 `f[n][m]`
77-
7877
* 状态转移:也就是我们要考虑 `f(i,j)` 如何求得,前面说到了 `p` 有三种字符,所以这里的状态转移也要分三种情况讨论:
79-
80-
1. `p[j]` 为普通字符:匹配的条件是前面的字符匹配,同时 `s` 中的第 `i` 个字符和 `p` 中的第 `j` 位相同。
81-
82-
`f(i,j) = f(i - 1, j - 1) && s[i] == p[j]`
83-
84-
2. `p[j]` 为 `'.'`:匹配的条件是前面的字符匹配, `s` 中的第 `i` 个字符可以是任意字符。
85-
86-
`f(i,j) = f(i - 1, j - 1) && p[j] == '.'`。
87-
88-
3. `p[j]``'*'`:读得 `p[j - 1]` 的字符,例如为字符 `a`。 然后根据 `a*` 实际匹配 `s``a` 的个数是 $0$ 个、$1$ 个、$2$ 个 ...
89-
90-
3.1. 当匹配为 $0$ 个:`f(i,j) = f(i, j - 2)`
91-
92-
3.2. 当匹配为 $1$ 个:`f(i,j) = f(i - 1, j - 2) && (s[i] == p[j - 1] || p[j - 1] == '.')`
93-
94-
3.3. 当匹配为 $2$ 个:`f(i,j) = f(i - 2, j - 2) && ((s[i] == p[j - 1] && s[i - 1] == p[j - 1]) || p[j] == '.')`
78+
1. `p[j]` 为普通字符:匹配的条件是前面的字符匹配,同时 `s` 中的第 `i` 个字符和 `p` 中的第 `j` 位相同。 即 `f(i,j) = f(i-1, j-1) && s[i] == p[j]`
79+
2. `p[j]``'.'`:匹配的条件是前面的字符匹配, `s` 中的第 `i` 个字符可以是任意字符。即 `f(i,j) = f(i-1, j-1) && p[j] == '.'`
80+
3. `p[j]``'*'`:读得 `p[j-1]` 的字符,例如为字符 `a`。 然后根据 `a*` 实际匹配 `s``a` 的个数是 $0$ 个、$1$ 个、$2$ 个 ...
81+
* 当匹配为 $0$ 个:`f(i,j) = f(i,j-2)`
82+
* 当匹配为 $1$ 个:`f(i,j) = f(i-1,j-2) && (s[i] == p[j-1] || p[j-1] == '.')`
83+
* 当匹配为 $2$ 个:`f(i,j) = f(i-2, j-2) && ((s[i] == p[j-1] && s[i-1] == p[j-1]) || p[j] == '.')`
9584

9685
**我们知道,通过「枚举」来确定 `*` 到底匹配多少个 `a` 这样的做法,算法复杂度是很高的。**
9786

9887
**我们需要挖掘一些「性质」来简化这个过程。**
9988

100-
![640.png](https://pic.leetcode-cn.com/1611397993-lmpHIZ-640.png)
89+
![](https://pic.leetcode-cn.com/1611397993-lmpHIZ-640.png)
10190

102-
代码:
91+
Java 代码:
10392
```Java
10493
class Solution {
10594
public boolean isMatch(String ss, String pp) {
10695
// 技巧:往原字符头部插入空格,这样得到 char 数组是从 1 开始,而且可以使得 f[0][0] = true,可以将 true 这个结果滚动下去
10796
int n = ss.length(), m = pp.length();
108-
ss = " " + ss;
109-
pp = " " + pp;
110-
char[] s = ss.toCharArray();
111-
char[] p = pp.toCharArray();
97+
ss = " " + ss; pp = " " + pp;
98+
char[] s = ss.toCharArray(), p = pp.toCharArray();
11299
// f(i,j) 代表考虑 s 中的 1~i 字符和 p 中的 1~j 字符 是否匹配
113100
boolean[][] f = new boolean[n + 1][m + 1];
114101
f[0][0] = true;
@@ -132,6 +119,67 @@ class Solution {
132119
}
133120
}
134121
```
122+
C++ 代码:
123+
```C++
124+
class Solution {
125+
public:
126+
bool isMatch(string s, string p) {
127+
int n = s.length(), m = p.length();
128+
s = " " + s; p = " " + p;
129+
vector<vector<bool>> f(n + 1, vector<bool>(m + 1, false));
130+
f[0][0] = true;
131+
for (int i = 0; i <= n; i++) {
132+
for (int j = 1; j <= m; j++) {
133+
if (j + 1 <= m && p[j + 1] == '*' && p[j] != '*') continue;
134+
if (i - 1 >= 0 && p[j] != '*') {
135+
f[i][j] = f[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
136+
} else if (p[j] == '*') {
137+
f[i][j] = (j - 2 >= 0 && f[i][j - 2]) || (i - 1 >= 0 && f[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.'));
138+
}
139+
}
140+
}
141+
return f[n][m];
142+
}
143+
};
144+
```
145+
Python 代码:
146+
```Python
147+
class Solution:
148+
def isMatch(self, s: str, p: str) -> bool:
149+
n, m = len(s), len(p)
150+
s, p = " " + s, " " + p
151+
f = [[False] * (m + 1) for _ in range(n + 1)]
152+
f[0][0] = True
153+
for i in range(n + 1):
154+
for j in range(1, m + 1):
155+
if j + 1 <= m and p[j + 1] == '*' and p[j] != '*':
156+
continue
157+
if i - 1 >= 0 and p[j] != '*':
158+
f[i][j] = f[i - 1][j - 1] and (s[i] == p[j] or p[j] == '.')
159+
elif p[j] == '*':
160+
f[i][j] = (j - 2 >= 0 and f[i][j - 2]) or (i - 1 >= 0 and f[i - 1][j] and (s[i] == p[j - 1] or p[j - 1] == '.'))
161+
return f[n][m]
162+
```
163+
TypeScript 代码:
164+
```TypeScript
165+
function isMatch(s: string, p: string): boolean {
166+
let n: number = s.length, m: number = p.length
167+
s = " " + s; p = " " + p;
168+
let f: boolean[][] = new Array(n + 1).fill(false).map(() => new Array(m + 1).fill(false));
169+
f[0][0] = true;
170+
for (let i: number = 0; i <= n; i++) {
171+
for (let j: number = 1; j <= m; j++) {
172+
if (j + 1 <= m && p.charAt(j + 1) === '*' && p.charAt(j) !== '*') continue;
173+
if (i - 1 >= 0 && p.charAt(j) !== '*') {
174+
f[i][j] = f[i - 1][j - 1] && (s.charAt(i) === p.charAt(j) || p.charAt(j) === '.');
175+
} else if (p.charAt(j) === '*') {
176+
f[i][j] = (j - 2 >= 0 && f[i][j - 2]) || (i - 1 >= 0 && f[i - 1][j] && (s.charAt(i) === p.charAt(j - 1) || p.charAt(j - 1) === '.'));
177+
}
178+
}
179+
}
180+
return f[n][m];
181+
};
182+
```
135183
* 时间复杂度:$n$ 表示 `s` 的长度,$m$ 表示 `p` 的长度,总共 $n \times m$ 个状态。复杂度为 $O(n \times m)$
136184
* 空间复杂度:使用了二维数组记录结果。复杂度为 $O(n \times m)$
137185

LeetCode/1001-1010/1004. 最大连续1的个数 III(中等).md

+128-14
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,27 @@ Tag : 「双指针」、「滑动窗口」、「二分」、「前缀和」
66

77

88

9-
给定一个由若干 $0$$1$ 组成的数组 `A`,我们最多可以将 $K$ 个值从 $0$ 变成 $1$
9+
给定一个由若干 01 组成的数组 `A`,我们最多可以将 `K` 个值从 0 变成 1
1010

11-
返回仅包含 $1$ 的最长(连续)子数组的长度。
11+
返回仅包含 1 的最长(连续)子数组的长度。
1212

1313

1414
示例 1:
1515
```
1616
输入:A = [1,1,1,0,0,0,1,1,1,1,0], K = 2
17+
1718
输出:6
19+
1820
解释:
1921
[1,1,1,0,0,1,1,1,1,1,1]
2022
粗体数字从 0 翻转到 1,最长的子数组长度为 6。
2123
```
2224
示例 2:
2325
```
2426
输入:A = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], K = 3
27+
2528
输出:10
29+
2630
解释:
2731
[0,0,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1]
2832
粗体数字从 0 翻转到 1,最长的子数组长度为 10。
@@ -50,7 +54,7 @@ Tag : 「双指针」、「滑动窗口」、「二分」、「前缀和」
5054
* 如果 $A[i]$ 本身就为 1 的话,无须消耗翻转次数,$f[i][j] = f[i - 1][j] + 1$。
5155
* 如果 $A[i]$ 本身不为 1 的话,由于定义是必须以 $A[i]$ 为结尾,因此必须要选择翻转该位置,$f[i][j] = f[i - 1][j - 1] + 1$。
5256

53-
代码:
57+
Java 代码:
5458
```Java
5559
class Solution {
5660
public int longestOnes(int[] nums, int k) {
@@ -96,23 +100,19 @@ class Solution {
96100

97101
**因此,对于某个确定的「左端点/右端点」而言,以「其最远右端点/最远左端点」为分割点的前缀和数轴,具有「二段性」。可以通过二分来找分割点。**
98102

99-
代码:
103+
Java 代码:
100104
```Java
101105
class Solution {
102106
public int longestOnes(int[] nums, int k) {
103-
int n = nums.length;
104-
int ans = 0;
107+
int n = nums.length, ans = 0;
105108
int[] sum = new int[n + 1];
106109
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1];
107110
for (int i = 0; i < n; i++) {
108111
int l = 0, r = i;
109112
while (l < r) {
110113
int mid = l + r >> 1;
111-
if (check(sum, mid, i, k)) {
112-
r = mid;
113-
} else {
114-
l = mid + 1;
115-
}
114+
if (check(sum, mid, i, k)) r = mid;
115+
else l = mid + 1;
116116
}
117117
if (check(sum, r, i, k)) ans = Math.max(ans, i - r + 1);
118118
}
@@ -124,6 +124,80 @@ class Solution {
124124
}
125125
}
126126
```
127+
C++ 代码:
128+
```C++
129+
class Solution {
130+
public:
131+
int longestOnes(vector<int>& nums, int k) {
132+
int n = nums.size(), ans = 0;
133+
vector<int> sum(n + 1, 0);
134+
for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1];
135+
for (int i = 0; i < n; i++) {
136+
int l = 0, r = i;
137+
while (l < r) {
138+
int mid = l + r >> 1;
139+
if (check(sum, mid, i, k)) r = mid;
140+
else l = mid + 1;
141+
}
142+
if (check(sum, r, i, k)) ans = max(ans, i - r + 1);
143+
}
144+
return ans;
145+
}
146+
bool check(const vector<int>& sum, int l, int r, int k) {
147+
int tol = sum[r + 1] - sum[l];
148+
int len = r - l + 1;
149+
return len - tol <= k;
150+
}
151+
};
152+
```
153+
Python 代码:
154+
```Python
155+
class Solution:
156+
def longestOnes(self, nums: List[int], k: int) -> int:
157+
n, ans = len(nums), 0
158+
sumv = [0] * (n + 1)
159+
for i in range(1, n + 1):
160+
sumv[i] = sumv[i - 1] + nums[i - 1]
161+
for i in range(n):
162+
l, r = 0, i
163+
while l < r:
164+
mid = l + r >> 1
165+
if self.check(sumv, mid, i, k):
166+
r = mid
167+
else:
168+
l = mid + 1
169+
if self.check(sumv, l, i, k):
170+
ans = max(ans, i - l + 1)
171+
return ans
172+
173+
def check(self, sumv, l, r, k):
174+
tol = sumv[r + 1] - sumv[l]
175+
lenv = r - l + 1
176+
return lenv - tol <= k
177+
```
178+
TypeScript 代码:
179+
```TypeScript
180+
function check(sum: number[], l: number, r: number, k: number): boolean {
181+
const tol = sum[r + 1] - sum[l];
182+
const len = r - l + 1;
183+
return len - tol <= k;
184+
}
185+
function longestOnes(nums: number[], k: number): number {
186+
let n = nums.length, ans = 0;
187+
const sum = new Array(n + 1).fill(0);
188+
for (let i = 1; i <= n; i++) sum[i] = sum[i - 1] + nums[i - 1];
189+
for (let i = 0; i < n; i++) {
190+
let l = 0, r = i;
191+
while (l < r) {
192+
let mid = l + r >> 1;
193+
if (check(sum, mid, i, k)) r = mid;
194+
else l = mid + 1;
195+
}
196+
if (check(sum, l, i, k)) ans = Math.max(ans, i - l + 1);
197+
}
198+
return ans;
199+
};
200+
```
127201
* 时间复杂度:$O(n\log{n})$
128202
* 空间复杂度:$O(n)$
129203

@@ -143,12 +217,11 @@ class Solution {
143217

144218
右端点一直右移,左端点在窗口不满足「`len - tol <= k`」的时候进行右移,即可做到线程扫描的复杂度。
145219

146-
代码:
220+
Java 代码:
147221
```Java
148222
class Solution {
149223
public int longestOnes(int[] nums, int k) {
150-
int n = nums.length;
151-
int ans = 0;
224+
int n = nums.length, ans = 0;
152225
for (int i = 0, j = 0, tot = 0; i < n; i++) {
153226
tot += nums[i];
154227
while ((i - j + 1) - tot > k) tot -= nums[j++];
@@ -158,6 +231,47 @@ class Solution {
158231
}
159232
}
160233
```
234+
C++ 代码:
235+
```C++
236+
class Solution {
237+
public:
238+
int longestOnes(vector<int>& nums, int k) {
239+
int n = nums.size(), ans = 0;
240+
for (int i = 0, j = 0, tot = 0; i < n; i++) {
241+
tot += nums[i];
242+
while ((i - j + 1) - tot > k) tot -= nums[j++];
243+
ans = max(ans, i - j + 1);
244+
}
245+
return ans;
246+
}
247+
};
248+
```
249+
Python 代码:
250+
```Python
251+
class Solution:
252+
def longestOnes(self, nums: List[int], k: int) -> int:
253+
n, ans = len(nums), 0
254+
j, tot = 0, 0
255+
for i in range(n):
256+
tot += nums[i]
257+
while (i - j + 1) - tot > k:
258+
tot -= nums[j]
259+
j += 1
260+
ans = max(ans, i - j + 1)
261+
return ans
262+
```
263+
TypeScript 代码:
264+
```TypeScript
265+
function longestOnes(nums: number[], k: number): number {
266+
let n = nums.length, ans = 0;
267+
for (let i = 0, j = 0, tot = 0; i < n; i++) {
268+
tot += nums[i];
269+
while ((i - j + 1) - tot > k) tot -= nums[j++];
270+
ans = Math.max(ans, i - j + 1);
271+
}
272+
return ans;
273+
};
274+
```
161275
* 时间复杂度:$O(n)$
162276
* 空间复杂度:$O(1)$
163277

0 commit comments

Comments
 (0)