Skip to content

Commit

Permalink
feat: add solutions to lc problems: No.1493,2730 (#2572)
Browse files Browse the repository at this point in the history
* No.1493.Longest Subarray of 1's After Deleting One Element
* No.2730.Find the Longest Semi-Repetitive Substring
  • Loading branch information
yanglbme authored Apr 12, 2024
1 parent c48370c commit c2699ed
Show file tree
Hide file tree
Showing 19 changed files with 484 additions and 225 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -50,48 +50,50 @@

### 方法一:枚举

枚举删除的位置 $i$,那么每一个位置 $i$ 的最长子数组长度为 $i$ 左边连续的 $1$ 的个数加上 $i$ 右边连续的 $1$ 的个数。
我们可以枚举每个删除的位置 $i$,然后计算左侧和右侧的连续 1 的个数,最后取最大值

因此,我们可以先遍历一遍数组,统计每个位置 $i$ 左边连续的 $1$ 的个数,记录在 `left` 数组;然后再从右向左遍历一遍数组,统计每个位置 $i$ 右边连续的 $1$ 的个数,记录在 `right` 数组,最后枚举删除的位置 $i$,求出最大值即可
具体地,我们使用两个长度为 $n+1$ 的数组 $left$ 和 $right$,其中 $left[i]$ 表示以 $nums[i-1]$ 结尾的连续 $1$ 的个数,而 $right[i]$ 表示以 $nums[i]$ 开头的连续 $1$ 的个数

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 `nums` 的长度。
最终答案即为 $\max_{0 \leq i < n} \{left[i] + right[i+1]\}$。

时间复杂度 $O(n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $nums$ 的长度。

<!-- tabs:start -->

```python
class Solution:
def longestSubarray(self, nums: List[int]) -> int:
n = len(nums)
left = [0] * n
right = [0] * n
for i in range(1, n):
if nums[i - 1] == 1:
left = [0] * (n + 1)
right = [0] * (n + 1)
for i, x in enumerate(nums, 1):
if x:
left[i] = left[i - 1] + 1
for i in range(n - 2, -1, -1):
if nums[i + 1] == 1:
for i in range(n - 1, -1, -1):
if nums[i]:
right[i] = right[i + 1] + 1
return max(a + b for a, b in zip(left, right))
return max(left[i] + right[i + 1] for i in range(n))
```

```java
class Solution {
public int longestSubarray(int[] nums) {
int n = nums.length;
int[] left = new int[n];
int[] right = new int[n];
for (int i = 1; i < n; ++i) {
int[] left = new int[n + 1];
int[] right = new int[n + 1];
for (int i = 1; i <= n; ++i) {
if (nums[i - 1] == 1) {
left[i] = left[i - 1] + 1;
}
}
for (int i = n - 2; i >= 0; --i) {
if (nums[i + 1] == 1) {
for (int i = n - 1; i >= 0; --i) {
if (nums[i] == 1) {
right[i] = right[i + 1] + 1;
}
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = Math.max(ans, left[i] + right[i]);
ans = Math.max(ans, left[i] + right[i + 1]);
}
return ans;
}
Expand All @@ -103,47 +105,158 @@ class Solution {
public:
int longestSubarray(vector<int>& nums) {
int n = nums.size();
vector<int> left(n);
vector<int> right(n);
for (int i = 1; i < n; ++i) {
if (nums[i - 1] == 1) {
vector<int> left(n + 1);
vector<int> right(n + 1);
for (int i = 1; i <= n; ++i) {
if (nums[i - 1]) {
left[i] = left[i - 1] + 1;
}
}
for (int i = n - 2; ~i; --i) {
if (nums[i + 1] == 1) {
for (int i = n - 1; ~i; --i) {
if (nums[i]) {
right[i] = right[i + 1] + 1;
}
}
int ans = 0;
for (int i = 0; i < n; ++i) {
ans = max(ans, left[i] + right[i]);
ans = max(ans, left[i] + right[i + 1]);
}
return ans;
}
};
```
```go
func longestSubarray(nums []int) int {
func longestSubarray(nums []int) (ans int) {
n := len(nums)
left := make([]int, n)
right := make([]int, n)
for i := 1; i < n; i++ {
left := make([]int, n+1)
right := make([]int, n+1)
for i := 1; i <= n; i++ {
if nums[i-1] == 1 {
left[i] = left[i-1] + 1
}
}
for i := n - 2; i >= 0; i-- {
if nums[i+1] == 1 {
for i := n - 1; i >= 0; i-- {
if nums[i] == 1 {
right[i] = right[i+1] + 1
}
}
ans := 0
for i := 0; i < n; i++ {
ans = max(ans, left[i]+right[i])
ans = max(ans, left[i]+right[i+1])
}
return
}
```

```ts
function longestSubarray(nums: number[]): number {
const n = nums.length;
const left: number[] = Array(n + 1).fill(0);
const right: number[] = Array(n + 1).fill(0);
for (let i = 1; i <= n; ++i) {
if (nums[i - 1]) {
left[i] = left[i - 1] + 1;
}
}
for (let i = n - 1; ~i; --i) {
if (nums[i]) {
right[i] = right[i + 1] + 1;
}
}
let ans = 0;
for (let i = 0; i < n; ++i) {
ans = Math.max(ans, left[i] + right[i + 1]);
}
return ans;
}
```

<!-- tabs:end -->

### 方法二:双指针

题目实际上是让我们找出一个最长的子数组,该子数组中最多只包含一个 $0$,删掉该子数组中的其中一个元素后,剩余的长度即为答案。

因此,我们可以用两个指针 $j$ 和 $i$ 分别指向子数组的左右边界,初始时 $j = 0$, $i = 0$。另外,我们用一个变量 $cnt$ 记录子数组中 $0$ 的个数。

接下来,我们移动右指针 $i$,如果 $nums[i] = 0$,则 $cnt$ 加 $1$。当 $cnt > 1$ 时,我们需要移动左指针 $j$,直到 $cnt \leq 1$。然后,我们更新答案,即 $ans = \max(ans, i - j)$。继续移动右指针 $i$,直到 $i$ 到达数组的末尾。

时间复杂度 $O(n)$,其中 $n$ 为数组 $nums$ 的长度。空间复杂度 $O(1)$。

<!-- tabs:start -->

```python
class Solution:
def longestSubarray(self, nums: List[int]) -> int:
ans = 0
cnt = j = 0
for i, x in enumerate(nums):
cnt += x ^ 1
while cnt > 1:
cnt -= nums[j] ^ 1
j += 1
ans = max(ans, i - j)
return ans
```

```java
class Solution {
public int longestSubarray(int[] nums) {
int ans = 0, n = nums.length;
for (int i = 0, j = 0, cnt = 0; i < n; ++i) {
cnt += nums[i] ^ 1;
while (cnt > 1) {
cnt -= nums[j++] ^ 1;
}
ans = Math.max(ans, i - j);
}
return ans;
}
}
```

```cpp
class Solution {
public:
int longestSubarray(vector<int>& nums) {
int ans = 0, n = nums.size();
for (int i = 0, j = 0, cnt = 0; i < n; ++i) {
cnt += nums[i] ^ 1;
while (cnt > 1) {
cnt -= nums[j++] ^ 1;
}
ans = max(ans, i - j);
}
return ans;
}
};
```
```go
func longestSubarray(nums []int) (ans int) {
cnt, j := 0, 0
for i, x := range nums {
cnt += x ^ 1
for ; cnt > 1; j++ {
cnt -= nums[j] ^ 1
}
ans = max(ans, i-j)
}
return ans
return
}
```

```ts
function longestSubarray(nums: number[]): number {
let [ans, cnt, j] = [0, 0, 0];
for (let i = 0; i < nums.length; ++i) {
cnt += nums[i] ^ 1;
while (cnt > 1) {
cnt -= nums[j++] ^ 1;
}
ans = Math.max(ans, i - j);
}
return ans;
}
```

Expand Down
Loading

0 comments on commit c2699ed

Please sign in to comment.