Skip to content

[pull] main from doocs:main #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Dec 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,7 @@
  <a href="https://github.com/doocs/leetcode"><img src="https://cdn-doocs.oss-cn-shenzhen.aliyuncs.com/gh/doocs/leetcode@main/images/how-to-contribute.svg" alt="how-to-contribute"></a>
</p>

[Gitpod.io](https://www.gitpod.io) 是一个免费的在线开发环境,你也可以使用它参与本项目。

<a href="https://gitpod.io/#https://github.com/doocs/leetcode" target="_blank" alt="Open in Gitpod"><img src="https://gitpod.io/button/open-in-gitpod.svg"></a>
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=149001365&machine=basicLinux32gb&location=SoutheastAsia)

## Stars 趋势

Expand Down
4 changes: 1 addition & 3 deletions README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,7 @@ I'm looking for long-term contributors/partners to this repo! Send me [PRs](http
  <a href="https://github.com/doocs/leetcode"><img src="https://cdn-doocs.oss-cn-shenzhen.aliyuncs.com/gh/doocs/leetcode@main/images/how-to-contribute.svg" alt="how-to-contribute"></a>
</p>

You can also contribute to [doocs/leetcode](https://github.com/doocs/leetcode) using [Gitpod.io](https://www.gitpod.io), a free online dev environment with a single click.

<a href="https://gitpod.io/#https://github.com/doocs/leetcode" target="_blank" alt="Open in Gitpod"><img src="https://gitpod.io/button/open-in-gitpod.svg"></a>
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=149001365&machine=basicLinux32gb&location=EastUs)

## Stargazers over time

Expand Down
16 changes: 8 additions & 8 deletions basic/searching/BinarySearch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,16 @@ int search(int left, int right) {
}
```

我们做二分题目时,可以按照以下步骤
做二分题目时,可以按照以下套路

1. 写出循环条件:`while (left < right)`,注意是 `left < right`,而非 `left <= right`
1. 循环体内,先无脑写出 `mid = (left + right) >> 1`
1. 根据具体题目,实现 `check()` 函数(有时很简单的逻辑,可以不定义 `check`),想一下究竟要用 `right = mid`(模板 1) 还是 `left = mid`(模板 2);
- 如果 `right = mid`,那么无脑写出 else 语句 `left = mid + 1`,并且不需要更改 mid 的计算,即保持 `mid = (left + right) >> 1`
- 如果 `left = mid`,那么无脑写出 else 语句 `right = mid - 1`,并且在 mid 计算时补充 +1,即 `mid = (left + right + 1) >> 1`。
1. 循环结束时,left 与 right 相等。
1. 写出循环条件 $left < right$
1. 循环体内,不妨先写 $mid = \lfloor \frac{left + right}{2} \rfloor$
1. 根据具体题目,实现 $check()$ 函数(有时很简单的逻辑,可以不定义 $check$),想一下究竟要用 $right = mid$(模板 $1$) 还是 $left = mid$(模板 $2$);
    - 如果 $right = mid$,那么写出 else 语句 $left = mid + 1$,并且不需要更改 mid 的计算,即保持 $mid = \lfloor \frac{left + right}{2} \rfloor$
    - 如果 $left = mid$,那么写出 else 语句 $right = mid - 1$,并且在 $mid$ 计算时补充 +1,即 $mid = \lfloor \frac{left + right + 1}{2} \rfloor$;
1. 循环结束时,$left$$right$ 相等。

注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 left 或者 right 是否满足题意即可。
注意,这两个模板的优点是始终保持答案位于二分区间内,二分结束条件对应的值恰好在答案所处的位置。 对于可能无解的情况,只要判断二分结束后的 $left$ 或者 $right$ 是否满足题意即可。

## 例题

Expand Down
13 changes: 13 additions & 0 deletions basic/searching/BinarySearch/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## Algorithm Templates

The essence of binary search is not "monotonicity", but "boundary". As long as a certain property is found that divides the entire interval into two, the boundary point can be found using binary search.

### Template 1

```java
Expand Down Expand Up @@ -40,6 +42,17 @@ int search(int left, int right) {
}
```

When doing binary search problems, you can follow the following routine:

1. Write out the loop condition $left < right$;
2. Inside the loop, you might as well write $mid = \lfloor \frac{left + right}{2} \rfloor$ first;
3. According to the specific problem, implement the $check()$ function (sometimes the logic is very simple, you can not define $check$), think about whether to use $right = mid$ (Template $1$) or $left = mid$ (Template $2$);
- If $right = mid$, then write the else statement $left = mid + 1$, and there is no need to change the calculation of $mid$, that is, keep $mid = \lfloor \frac{left + right}{2} \rfloor$;
- If $left = mid$, then write the else statement $right = mid - 1$, and add +1 when calculating $mid$, that is, $mid = \lfloor \frac{left + right + 1}{2} \rfloor$;
4. When the loop ends, $left$ equals $right$.

Note that the advantage of these two templates is that they always keep the answer within the binary search interval, and the value corresponding to the end condition of the binary search is exactly at the position of the answer. For the case that may have no solution, just check whether the $left$ or $right$ after the binary search ends satisfies the problem.

## Examples

- [Find First and Last Position of Element in Sorted Array](/solution/0000-0099/0034.Find%20First%20and%20Last%20Position%20of%20Element%20in%20Sorted%20Array/README_EN.md)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Description

<p>Given a <strong>1-indexed</strong> array of integers <code>numbers</code> that is already <strong><em>sorted in non-decreasing order</em></strong>, find two numbers such that they add up to a specific <code>target</code> number. Let these two numbers be <code>numbers[index<sub>1</sub>]</code> and <code>numbers[index<sub>2</sub>]</code> where <code>1 &lt;= index<sub>1</sub> &lt; index<sub>2</sub> &lt;&nbsp;numbers.length</code>.</p>
<p>Given a <strong>1-indexed</strong> array of integers <code>numbers</code> that is already <strong><em>sorted in non-decreasing order</em></strong>, find two numbers such that they add up to a specific <code>target</code> number. Let these two numbers be <code>numbers[index<sub>1</sub>]</code> and <code>numbers[index<sub>2</sub>]</code> where <code>1 &lt;= index<sub>1</sub> &lt; index<sub>2</sub> &lt;= numbers.length</code>.</p>

<p>Return<em> the indices of the two numbers, </em><code>index<sub>1</sub></code><em> and </em><code>index<sub>2</sub></code><em>, <strong>added by one</strong> as an integer array </em><code>[index<sub>1</sub>, index<sub>2</sub>]</code><em> of length 2.</em></p>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<p>You are given an array of strings <code>words</code> and a string <code>chars</code>.</p>

<p>A string is <strong>good</strong> if it can be formed by characters from chars (each character can only be used once).</p>
<p>A string is <strong>good</strong> if it can be formed by characters from <code>chars</code> (each character can only be used once).</p>

<p>Return <em>the sum of lengths of all good strings in words</em>.</p>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@

那么最终答案就是 $n - \max(left[i] + right[i] - 1)$,其中 $1 \leq i \leq n$,并且 $left[i] \gt 1$ 且 $right[i] \gt 1$。

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

<!-- tabs:start -->

Expand Down Expand Up @@ -193,8 +193,8 @@ func minimumMountainRemovals(nums []int) int {
```ts
function minimumMountainRemovals(nums: number[]): number {
const n = nums.length;
const left = new Array(n).fill(1);
const right = new Array(n).fill(1);
const left = Array(n).fill(1);
const right = Array(n).fill(1);
for (let i = 1; i < n; ++i) {
for (let j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
Expand All @@ -219,6 +219,41 @@ function minimumMountainRemovals(nums: number[]): number {
}
```

### **TypeScript**

```ts
impl Solution {
pub fn minimum_mountain_removals(nums: Vec<i32>) -> i32 {
let n = nums.len();
let mut left = vec![1; n];
let mut right = vec![1; n];
for i in 1..n {
for j in 0..i {
if nums[i] > nums[j] {
left[i] = left[i].max(left[j] + 1);
}
}
}
for i in (0..n - 1).rev() {
for j in i + 1..n {
if nums[i] > nums[j] {
right[i] = right[i].max(right[j] + 1);
}
}
}

let mut ans = 0;
for i in 0..n {
if left[i] > 1 && right[i] > 1 {
ans = ans.max(left[i] + right[i] - 1);
}
}

(n as i32) - ans
}
}
```

### **...**

```
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,16 @@

## Solutions

**Solution 1: Dynamic Programming**

This problem can be transformed into finding the longest increasing subsequence and the longest decreasing subsequence.

We define $left[i]$ as the length of the longest increasing subsequence ending with $nums[i]$, and define $right[i]$ as the length of the longest decreasing subsequence starting with $nums[i]$.

Then the final answer is $n - \max(left[i] + right[i] - 1)$, where $1 \leq i \leq n$, and $left[i] \gt 1$ and $right[i] \gt 1$.

The time complexity is $O(n^2)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $nums$.

<!-- tabs:start -->

### **Python3**
Expand Down Expand Up @@ -173,8 +183,8 @@ func minimumMountainRemovals(nums []int) int {
```ts
function minimumMountainRemovals(nums: number[]): number {
const n = nums.length;
const left = new Array(n).fill(1);
const right = new Array(n).fill(1);
const left = Array(n).fill(1);
const right = Array(n).fill(1);
for (let i = 1; i < n; ++i) {
for (let j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
Expand All @@ -199,6 +209,41 @@ function minimumMountainRemovals(nums: number[]): number {
}
```

### **TypeScript**

```ts
impl Solution {
pub fn minimum_mountain_removals(nums: Vec<i32>) -> i32 {
let n = nums.len();
let mut left = vec![1; n];
let mut right = vec![1; n];
for i in 1..n {
for j in 0..i {
if nums[i] > nums[j] {
left[i] = left[i].max(left[j] + 1);
}
}
}
for i in (0..n - 1).rev() {
for j in i + 1..n {
if nums[i] > nums[j] {
right[i] = right[i].max(right[j] + 1);
}
}
}

let mut ans = 0;
for i in 0..n {
if left[i] > 1 && right[i] > 1 {
ans = ans.max(left[i] + right[i] - 1);
}
}

(n as i32) - ans
}
}
```

### **...**

```
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
impl Solution {
pub fn minimum_mountain_removals(nums: Vec<i32>) -> i32 {
let n = nums.len();
let mut left = vec![1; n];
let mut right = vec![1; n];
for i in 1..n {
for j in 0..i {
if nums[i] > nums[j] {
left[i] = left[i].max(left[j] + 1);
}
}
}
for i in (0..n - 1).rev() {
for j in i + 1..n {
if nums[i] > nums[j] {
right[i] = right[i].max(right[j] + 1);
}
}
}

let mut ans = 0;
for i in 0..n {
if left[i] > 1 && right[i] > 1 {
ans = ans.max(left[i] + right[i] - 1);
}
}

(n as i32) - ans
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
function minimumMountainRemovals(nums: number[]): number {
const n = nums.length;
const left = new Array(n).fill(1);
const right = new Array(n).fill(1);
const left = Array(n).fill(1);
const right = Array(n).fill(1);
for (let i = 1; i < n; ++i) {
for (let j = 0; j < i; ++j) {
if (nums[i] > nums[j]) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ nums[3] + nums[0] = 3 + 1 = 4.

可以发现,这实际上是在对一个连续区间内的元素进行加减操作,因此我们可以使用差分数组来实现。

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

<!-- tabs:start -->

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,30 @@ Therefore, nums[i] + nums[n-1-i] = 4 for every i, so nums is complementary.

## Solutions

**Solution 1: Difference Array**

Let's denote $a$ as the smaller value between $nums[i]$ and $nums[n-i-1]$, and $b$ as the larger value between $nums[i]$ and $nums[n-i-1]$.

Suppose that after replacement, the sum of the two numbers is $x$. From the problem, we know that the minimum value of $x$ is $2$, which means both numbers are replaced by $1$; the maximum value is $2 \times limit$, which means both numbers are replaced by $limit$. Therefore, the range of $x$ is $[2,... 2 \times limit]$.

How to find the minimum number of replacements for different $x$?

We analyze and find:

- If $x = a + b$, then the number of replacements we need is $0$, which means the current pair of numbers already meets the complement requirement;
- Otherwise, if $1 + a \le x \le limit + b $, then the number of replacements we need is $1$, which means we can replace one of the numbers;
- Otherwise, if $2 \le x \le 2 \times limit$, then the number of replacements we need is $2$, which means we need to replace both numbers.

Therefore, we can iterate over each pair of numbers and perform the following operations:

1. First, add $2$ to the number of operations required in the range $[2,... 2 \times limit]$.
1. Then, subtract $1$ from the number of operations required in the range $[1 + a,... limit + b]$.
1. Finally, subtract $1$ from the number of operations required in the range $[a + b,... a + b]$.

We can see that this is actually adding and subtracting elements in a continuous interval, so we can use a difference array to implement it.

The time complexity is $O(n)$, and the space complexity is $O(n)$. Here, $n$ is the length of the array $nums$.

<!-- tabs:start -->

### **Python3**
Expand Down
12 changes: 12 additions & 0 deletions solution/1600-1699/1675.Minimize Deviation in Array/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@

## Solutions

**Solution 1: Greedy + Priority Queue**

Intuitively, to get the minimum offset of the array, we need to decrease the maximum value of the array and increase the minimum value of the array.

Since there are two operations that can be performed each time: multiply an odd number by $2$; divide an even number by $2$, the situation is more complex. We can multiply all odd numbers by $2$ to convert them into even numbers, which is equivalent to having only one division operation. The division operation can only reduce a certain number, and only by reducing the maximum value can the result be more optimal.

Therefore, we use a priority queue (max heap) to maintain the maximum value of the array. Each time we take out the top element of the heap for division operation, put the new value into the heap, and update the minimum value and the minimum value of the difference between the top element of the heap and the minimum value.

When the top element of the heap is an odd number, the operation stops.

The time complexity is $O(n\log n \times \log m)$. Where $n$ and $m$ are the length of the array `nums` and the maximum element of the array, respectively. Since the maximum element in the array is divided by $2$ at most $O(\log m)$ times, all elements are divided by $2$ at most $O(n\log m)$ times. Each time the heap is popped and put into operation, the time complexity is $O(\log n)$. Therefore, the total time complexity is $O(n\log n \times \log m)$.

<!-- tabs:start -->

### **Python3**
Expand Down
15 changes: 15 additions & 0 deletions solution/1600-1699/1678.Goal Parser Interpretation/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@ The final concatenated result is &quot;Goal&quot;.

## Solutions

**Solution 1: String Replacement**

According to the problem, we only need to replace `"()"` with `'o'` and `"(al)"` with `"al"` in the string `command`.

**Solution 2: String Iteration**

We can also iterate over the string `command`. For each character $c$:

- If it is `'G'`, directly add $c$ to the result string;
- If it is `'('`, check if the next character is `')'`. If it is, add `'o'` to the result string. Otherwise, add `"al"` to the result string.

After the iteration, return the result string.

The time complexity is $O(n)$, and the space complexity is $O(1)$.

<!-- tabs:start -->

### **Python3**
Expand Down
10 changes: 5 additions & 5 deletions solution/1600-1699/1679.Max Number of K-Sum Pairs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@

**方法一:排序**

我们对 `nums` 进行排序。然后 $l$, $r$ 分别指向 `nums` 首尾元素,判断两整数之和 $s$ 与 $k$ 的大小关系。
我们对 $nums$ 进行排序。然后 $l$, $r$ 分别指向 $nums$ 首尾元素,判断两整数之和 $s$ 与 $k$ 的大小关系。

- 若 $s = k$,说明找到了两个整数,满足和为 $k$,答案加一,然后 $l$, $r$ 向中间移动;
- 若 $s \gt k$,则 $r$ 指针向左移动;
Expand All @@ -58,17 +58,17 @@

循环结束,返回答案。

时间复杂度 $O(n\times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为 `nums` 的长度。
时间复杂度 $O(n \times \log n)$,空间复杂度 $O(\log n)$。其中 $n$ 为 $nums$ 的长度。

**方法二:哈希表**

我们使用哈希表 `cnt` 记录当前剩余整数及其出现的次数。
我们使用哈希表 $cnt$ 记录当前剩余整数及其出现的次数。

遍历 `nums`,对于当前整数 $x$,判断 $k - x$ 是否在 `cnt` 中,若存在,则说明找到了两个整数,满足和为 $k$,答案加一,然后将 $k - x$ 的出现次数减一;否则,将 $x$ 的出现次数加一。
遍历 $nums$,对于当前整数 $x$,判断 $k - x$ 是否在 $cnt$ 中,若存在,则说明找到了两个整数,满足和为 $k$,答案加一,然后将 $k - x$ 的出现次数减一;否则,将 $x$ 的出现次数加一。

遍历结束,返回答案。

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

<!-- tabs:start -->

Expand Down
Loading