Skip to content

Commit

Permalink
更新题解列表
Browse files Browse the repository at this point in the history
  • Loading branch information
itcharge committed Sep 11, 2023
1 parent 87ba74a commit 2876ed0
Show file tree
Hide file tree
Showing 23 changed files with 393 additions and 171 deletions.
16 changes: 8 additions & 8 deletions Solutions/0015. 三数之和.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

## 题目大意

**描述**:给定一个整数数组 `nums`
**描述**:给定一个整数数组 $nums$

**要求**:判断 `nums` 中是否存在三个元素 `a``b``c`,满足 `a + b + c == 0`。要求找出所有满足要求的不重复的三元组。
**要求**:判断 $nums$ 中是否存在三个元素 $a$、$b$、$c$,满足 $a + b + c == 0$。要求找出所有满足要求的不重复的三元组。

**说明**

Expand All @@ -34,15 +34,15 @@

### 思路 1:对撞指针

直接三重遍历查找 `a``b``c` 的时间复杂度是:$O(n^3)$。我们可以通过一些操作来降低复杂度。
直接三重遍历查找 $a$、$b$、$c$ 的时间复杂度是:$O(n^3)$。我们可以通过一些操作来降低复杂度。

先将数组进行排序,以保证按顺序查找 `a``b``c` 时,元素值为升序,从而保证所找到的三个元素是不重复的。同时也方便下一步使用双指针减少一重遍历。时间复杂度为:$O(nlogn)$。
先将数组进行排序,以保证按顺序查找 $a$、$b$、$c$ 时,元素值为升序,从而保证所找到的三个元素是不重复的。同时也方便下一步使用双指针减少一重遍历。时间复杂度为:$O(nlogn)$。

第一重循环遍历 `a`,对于每个 `a` 元素,从 `a` 元素的下一个位置开始,使用对撞指针 `left``right``left` 指向 `a` 元素的下一个位置,`right` 指向末尾位置。先将 `left` 右移、`right` 左移去除重复元素,再进行下边的判断。
第一重循环遍历 $a$,对于每个 $a$ 元素,从 $a$ 元素的下一个位置开始,使用对撞指针 $left$,$right$。$left$ 指向 $a$ 元素的下一个位置,$right$ 指向末尾位置。先将 $left$ 右移、$right$ 左移去除重复元素,再进行下边的判断。

1. 如果 `nums[a] + nums[left] + nums[right] = 0`,则得到一个解,将其加入答案数组中,并继续将 `left` 右移,`right` 左移;
2. 如果 `nums[a] + nums[left] + nums[right] > 0`,说明 `nums[right]` 值太大,将 `right` 向左移;
3. 如果 `nums[a] + nums[left] + nums[right] < 0`,说明 `nums[left]` 值太小,将 `left` 右移。
1. 如果 $nums[a] + nums[left] + nums[right] == 0$,则得到一个解,将其加入答案数组中,并继续将 $left$ 右移,$right$ 左移;
2. 如果 $nums[a] + nums[left] + nums[right] > 0$,说明 $nums[right]$ 值太大,将 $right$ 向左移;
3. 如果 $nums[a] + nums[left] + nums[right] < 0$,说明 $nums[left]$ 值太小,将 $left$ 右移。

### 思路 1:代码

Expand Down
12 changes: 6 additions & 6 deletions Solutions/0027. 移除元素.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

## 题目大意

**描述**:给定一个数组 `nums`,和一个值 `val`
**描述**:给定一个数组 $nums$,和一个值 $val$

**要求**:不使用额外数组空间,将数组中所有数值等于 `val` 值的元素移除掉,并且返回新数组的长度。
**要求**:不使用额外数组空间,将数组中所有数值等于 $val$ 值的元素移除掉,并且返回新数组的长度。

**说明**

Expand Down Expand Up @@ -37,10 +37,10 @@

### 思路 1:快慢指针

1. 使用两个指针 `slow``fast``slow` 指向处理好的非 `val` 值元素数组的尾部,`fast` 指针指向当前待处理元素。
2. 不断向右移动 `fast` 指针,每次移动到非 `val` 值的元素,则将左右指针对应的数交换,交换同时将 `slow` 右移。
3. 这样就将非 `val` 值的元素进行前移,`slow` 指针左边均为处理好的非 `val` 值元素,而从 `slow` 指针指向的位置开始, `fast` 指针左边都为 `val `值。
4. 遍历结束之后,则所有 `val` 值元素都移动到了右侧,且保持了非零数的相对位置。此时 `slow` 就是新数组的长度。
1. 使用两个指针 $slow$,$fast$。$slow$ 指向处理好的非 $val$ 值元素数组的尾部,$fast$ 指针指向当前待处理元素。
2. 不断向右移动 $fast$ 指针,每次移动到非 $val$ 值的元素,则将左右指针对应的数交换,交换同时将 $slow$ 右移。
3. 这样就将非 $val$ 值的元素进行前移,$slow$ 指针左边均为处理好的非 $val$ 值元素,而从 $slow$ 指针指向的位置开始, $fast$ 指针左边都为 $val $值。
4. 遍历结束之后,则所有 $val$ 值元素都移动到了右侧,且保持了非零数的相对位置。此时 $slow$ 就是新数组的长度。

### 思路 1:代码

Expand Down
32 changes: 16 additions & 16 deletions Solutions/0033. 搜索旋转排序数组.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

## 题目大意

**描述**:给定一个整数数组 `nums`,数组中值互不相同。给定的 `nums` 是经过升序排列后的又进行了「旋转」操作的。再给定一个整数 `target`
**描述**:给定一个整数数组 $nums$,数组中值互不相同。给定的 $nums$ 是经过升序排列后的又进行了「旋转」操作的。再给定一个整数 $target$

**要求**:从 `nums` 中找到 `target` 所在位置,如果找到,则返回对应下标,找不到则返回 `-1`
**要求**:从 $nums$ 中找到 $target$ 所在位置,如果找到,则返回对应下标,找不到则返回 $-1$

**说明**

- 旋转操作:升序排列的数组 nums 在预先未知的第 k 个位置进行了右移操作,变成了 `[nums[k]], nums[k+1], ... , nums[n-1], ... , nums[0], nums[1], ... , nums[k-1]`
- 旋转操作:升序排列的数组 nums 在预先未知的第 k 个位置进行了右移操作,变成了 $[nums[k]], nums[k+1], ... , nums[n-1], ... , nums[0], nums[1], ... , nums[k-1]$

**示例**

Expand All @@ -33,7 +33,7 @@

### 思路 1:二分查找

原本为升序排列的数组 `nums` 经过「旋转」之后,会有两种情况,第一种就是原先的升序序列,另一种是两段升序的序列。
原本为升序排列的数组 $nums$ 经过「旋转」之后,会有两种情况,第一种就是原先的升序序列,另一种是两段升序的序列。

```python
*
Expand All @@ -53,24 +53,24 @@
*
```

最直接的办法就是遍历一遍,找到目标值 `target`。但是还可以有更好的方法。考虑用二分查找来降低算法的时间复杂度。
最直接的办法就是遍历一遍,找到目标值 $target$。但是还可以有更好的方法。考虑用二分查找来降低算法的时间复杂度。

我们将旋转后的数组看成左右两个升序部分:左半部分和右半部分。

有人会说第一种情况不是只有一个部分吗?其实我们可以把第一种情况中的整个数组看做是左半部分,然后右半部分为空数组。

然后创建两个指针 `left``right`,分别指向数组首尾。让后计算出两个指针中间值 `mid`。将 `mid` 与两个指针做比较,并考虑与 `target` 的关系。
然后创建两个指针 $left$、$right$,分别指向数组首尾。让后计算出两个指针中间值 $mid$。将 $mid$ 与两个指针做比较,并考虑与 $target$ 的关系。

- 如果 `mid[mid] == target`,说明找到了 `target`,直接返回下标。
- 如果 `nums[mid] nums[left]`,则 `mid` 在左半部分(因为右半部分值都比 `nums[left]` 小)。
- 如果 `nums[mid] target`,并且 `target nums[left]`,则 `target` 在左半部分,并且在 `mid` 左侧,此时应将 `right` 左移到 `mid - 1` 位置。
- 否则如果 `nums[mid] target`,则 `target` 在左半部分,并且在 `mid` 右侧,此时应将 `left` 右移到 `mid + 1` 位置。
- 否则如果 `nums[left] > target`,则 `target` 在右半部分,应将 `left` 移动到 `mid + 1` 位置。
- 如果 $mid[mid] == target$,说明找到了 $target$,直接返回下标。
- 如果 $nums[mid] \ge nums[left]$,则 $mid$ 在左半部分(因为右半部分值都比 $nums[left]$ 小)。
- 如果 $nums[mid] \ge target$,并且 $target \ge nums[left]$,则 $target$ 在左半部分,并且在 $mid$ 左侧,此时应将 $right$ 左移到 $mid - 1$ 位置。
- 否则如果 $nums[mid] \le target$,则 $target$ 在左半部分,并且在 $mid$ 右侧,此时应将 $left$ 右移到 $mid + 1$ 位置。
- 否则如果 $nums[left] > target$,则 $target$ 在右半部分,应将 $left$ 移动到 $mid + 1$ 位置。

- 如果 `nums[mid] < nums[left]`,则 `mid` 在右半部分(因为右半部分值都比 `nums[left]` 小)。
- 如果 `nums[mid] < target`,并且 `target nums[right]`,则 `target` 在右半部分,并且在 `mid` 右侧,此时应将 `left` 右移到 `mid + 1` 位置。
- 否则如果 `nums[mid] target`,则 `target` 在右半部分,并且在 `mid` 左侧,此时应将 `right` 左移到 `mid - 1` 位置。
- 否则如果 `nums[right] < target`,则 `target` 在左半部分,应将 `right` 左移到 `mid - 1` 位置。
- 如果 $nums[mid] < nums[left]$,则 $mid$ 在右半部分(因为右半部分值都比 $nums[left]$ 小)。
- 如果 $nums[mid] < target$,并且 $target \le nums[right]$,则 $target$ 在右半部分,并且在 $mid$ 右侧,此时应将 $left$ 右移到 $mid + 1$ 位置。
- 否则如果 $nums[mid] \ge target$,则 $target$ 在右半部分,并且在 $mid$ 左侧,此时应将 $right$ 左移到 $mid - 1$ 位置。
- 否则如果 $nums[right] < target$,则 $target$ 在左半部分,应将 $right$ 左移到 $mid - 1$ 位置。

### 思路 1:代码

Expand Down Expand Up @@ -100,6 +100,6 @@ class Solution:

### 思路 1:复杂度分析

- **时间复杂度**:$O(\log_2 n)$。二分查找算法的时间复杂度为 $O(\log_2 n)$。
- **时间复杂度**:$O(\log n)$。二分查找算法的时间复杂度为 $O(\log n)$。
- **空间复杂度**:$O(1)$。只用到了常数空间存放若干变量。

14 changes: 7 additions & 7 deletions Solutions/0035. 搜索插入位置.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

## 题目大意

**描述**:给定一个排好序的数组 `nums`,以及一个目标值 `target`
**描述**:给定一个排好序的数组 $nums$,以及一个目标值 $target$

**要求**:在数组中找到目标值,并返回下标。如果找不到,则返回目标值按顺序插入数组的位置。

Expand All @@ -29,15 +29,15 @@

### 思路 1:二分查找

设定左右节点为数组两端,即 `left = 0``right = len(nums) - 1`,代表待查找区间为 `[left, right]`(左闭右闭)。
设定左右节点为数组两端,即 `left = 0``right = len(nums) - 1`,代表待查找区间为 $[left, right]$(左闭右闭)。

取两个节点中心位置 `mid`,先比较中心位置值 `nums[mid]` 与目标值 `target` 的大小。
取两个节点中心位置 $mid$,先比较中心位置值 $nums[mid]$ 与目标值 $target$ 的大小。

- 如果中心位置值 `nums[mid]` 与目标值 `target` 相等,则当前中心位置为待插入数组的位置。
- 如果中心位置值 `nums[mid]` 小于目标值 `target`,则将左节点设置为 `mid + 1`,然后继续在右区间 `[mid + 1, right]` 搜索。
- 如果中心位置值 `nums[mid]` 大于目标值 `target`,则将右节点设置为 `mid - 1`,然后继续在左区间 `[left, mid - 1]` 搜索。
- 如果 $target == nums[mid]$,则当前中心位置为待插入数组的位置。
- 如果 $target > nums[mid]$,则将左节点设置为 $mid + 1$,然后继续在右区间 $[mid + 1, right]$ 搜索。
- 如果 $target < nums[mid]$,则将右节点设置为 $mid - 1$,然后继续在左区间 $[left, mid - 1]$ 搜索。

直到查找到目标值返回待插入数组的位置,或者等到 `left > right` 时停止查找,此时 `left` 所在位置就是待插入数组的位置。
直到查找到目标值返回待插入数组的位置,或者等到 $left > right$ 时停止查找,此时 $left$ 所在位置就是待插入数组的位置。

### 思路 1:二分查找代码

Expand Down
20 changes: 15 additions & 5 deletions Solutions/0059. 螺旋矩阵 II.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,22 @@

## 题目大意

给你一个正整数 `n`
给你一个正整数 $n$

要求:生成一个包含 `1` 到 $n^2$ 所有元素,且元素按顺时针顺序螺旋排列的 `n x n` 正方形矩阵 `matrix`
要求:生成一个包含 $1 \sim n^2$ 的所有元素,且元素按顺时针顺序螺旋排列的 $n \times n$ 正方形矩阵 $matrix$

## 解题思路

这道题跟「[54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)」思路是一样的。定义上、下、左、右的边界,然后按照逆时针的顺序从边界上依次给数组相应位置赋值。
### 思路 1:模拟

当访问完当前边界之后,要更新一下边界位置,缩小范围,方便下一轮进行访问
这道题跟「[54. 螺旋矩阵](https://leetcode.cn/problems/spiral-matrix/)」思路是一样的

## 代码
1. 构建一个 $n \times n$ 大小的数组 $matrix$ 存储答案。然后定义一下上、下、左、右的边界。
2. 然后按照逆时针的顺序从边界上依次给数组 $matrix$ 相应位置赋值。
3. 当访问完当前边界之后,要更新一下边界位置,缩小范围,方便下一轮进行访问。
4. 最后返回 $matrix$。

### 思路 1:代码

```python
class Solution:
Expand Down Expand Up @@ -51,3 +56,8 @@ class Solution:
return matrix
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(n^2)$。
- **空间复杂度**:$O(n^2)$。

4 changes: 2 additions & 2 deletions Solutions/0069. x 的平方根.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

## 题目大意

**要求**:实现 `int sqrt(int x)` 函数。计算并返回 `x` 的平方根(只保留整数部分),其中 `x` 是非负整数。
**要求**:实现 `int sqrt(int x)` 函数。计算并返回 $x$ 的平方根(只保留整数部分),其中 $x$ 是非负整数。

**说明**

Expand All @@ -32,7 +32,7 @@

### 思路 1:二分查找

因为求解的是 `x` 开方的整数部分。所以我们可以从 `0` ~ `x` 的范围进行遍历,找到 $k^2 \le x$ 的最大结果。
因为求解的是 $x$ 开方的整数部分。所以我们可以从 $0 \sim x$ 的范围进行遍历,找到 $k^2 \le x$ 的最大结果。

为了减少算法的时间复杂度,我们使用二分查找的方法来搜索答案。

Expand Down
57 changes: 46 additions & 11 deletions Solutions/0073. 矩阵置零.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,27 +5,57 @@

## 题目大意

给定一个 `m * n` 大小的矩阵。
**描述**给定一个 $m \times n$ 大小的矩阵 $matrix$

要求:如果一个元素为 `0`,则将其所在行和列所有元素都置为 `0`。要求使用原地算法,并使用常量空间解决
**要求**:如果一个元素为 $0$,则将其所在行和列所有元素都置为 $0$

## 解题思路
**说明**

- 请使用「原地」算法。
- $m == matrix.length$。
- $n == matrix[0].length$。
- $1 \le m, n \le 200$。
- $-2^{31} \le matrix[i][j] \le 2^{31} - 1$。
- **进阶**
- 一个直观的解决方案是使用 $O(m \times n)$ 的额外空间,但这并不是一个好的解决方案。
- 一个简单的改进方案是使用 $O(m + n)$ 的额外空间,但这仍然不是最好的解决方案。
- 你能想出一个仅使用常量空间的解决方案吗?


**示例**

- 示例 1:
- ![](https://assets.leetcode.com/uploads/2020/08/17/mat1.jpg)

```python
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
```

直观上可以使用两个数组来标记行和列出现 `0` 的情况,但这样空间复杂度就是 $O(m+n)$ 了,不符合题意。
- 示例 2:

考虑使用数组原本的元素进行记录出现 `0` 的情况。
![](https://assets.leetcode.com/uploads/2020/08/17/mat2.jpg)

设定两个变量 `flag_row0``flag_col0` 来标记第一行、第一列是否出现了 `0`
```
输入:matrix = [[1,1,1],[1,0,1],[1,1,1]]
输出:[[1,0,1],[0,0,0],[1,0,1]]
```

接下来我们使用数组第一行、第一列来标记 `0` 的情况。
## 解题思路

对数组除第一行、第一列之外的每个元素进行遍历,如果某个元素出现 `0` 了,则使用数组的第一行、第一列对应位置来存储 `0` 的标记。
### 思路 1:使用标记变量

再对数组除第一行、第一列之外的每个元素进行遍历,通过对第一行、第一列的标记 `0` 情况,进行置为 `0` 的操作
直观上可以使用两个数组来标记行和列出现 $0$ 的情况,但这样空间复杂度就是 $O(m+n)$ 了,不符合题意

然后再根据 `flag_row0``flag_col0` 的标记情况,对第一行、第一列进行置为 `0` 的操作
考虑使用数组原本的元素进行记录出现 $0$ 的情况

## 代码
1. 设定两个变量 $flag\underline{}row0$、$flag\underline{}col0$ 来标记第一行、第一列是否出现了 $0$。
2. 接下来我们使用数组第一行、第一列来标记 $0$ 的情况。
3. 对数组除第一行、第一列之外的每个元素进行遍历,如果某个元素出现 $0$ 了,则使用数组的第一行、第一列对应位置来存储 $0$ 的标记。
4. 再对数组除第一行、第一列之外的每个元素进行遍历,通过对第一行、第一列的标记 $0$ 情况,进行置为 $0$ 的操作。
5. 最后再根据 $flag\underline{}row0$、$flag\underline{}col0$ 的标记情况,对第一行、第一列进行置为 $0$ 的操作。

### 思路 1:代码

```python
class Solution:
Expand Down Expand Up @@ -63,3 +93,8 @@ class Solution:
matrix[0][j] = 0
```

### 思路 1:复杂度分析

- **时间复杂度**:$O(m \times n)$。
- **空间复杂度**:$O(1)$。

21 changes: 10 additions & 11 deletions Solutions/0080. 删除有序数组中的重复项 II.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@

## 题目大意

**描述**:给定一个有序数组 `nums`
**描述**:给定一个有序数组 $nums$

**要求**:在原数组空间基础上删除重复出现 `2` 次以上的元素,并返回删除后数组的新长度。
**要求**:在原数组空间基础上删除重复出现 $2$ 次以上的元素,并返回删除后数组的新长度。

**说明**

- $1 \le nums.length \le 3 * 10^4$。
- $-10^4 \le nums[i] \le 10^4$。
- `nums` 已按升序排列。
- $nums$ 已按升序排列。

**示例**

Expand All @@ -39,12 +39,12 @@

因为数组是有序的,所以重复元素必定是连续的。可以使用快慢指针来解决。具体做法如下:

1. 使用两个指针 `slow``fast``slow` 指针指向即将放置元素的位置,`fast` 指针指向当前待处理元素。
2. 本题要求相同元素最多出现 2 次,并且 `slow - 2` 是上上次放置了元素的位置。则应该检查 `nums[slow - 2]` 和当前待处理元素 `nums[fast]` 是否相同。
1. 如果 `nums[slow - 2] == nums[fast]` 时,此时必有 `nums[slow - 2] == nums[slow - 1] == nums[fast]`,则当前 `nums[fast]` 不保留,直接向右移动快指针 `fast`
2. 如果 `nums[slow - 2] != nums[fast]` 时,则保留 `nums[fast]`。将 `nums[fast]` 赋值给 `nums[slow]` ,同时将 `slow` 右移。然后再向右移动快指针 `fast`
3. 这样 `slow` 指针左边均为处理好的数组元素,而从 `slow` 指针指向的位置开始, `fast` 指针左边都为舍弃的重复元素。
4. 遍历结束之后,此时 `slow` 就是新数组的长度。
1. 使用两个指针 $slow$,$fast$。$slow$ 指针指向即将放置元素的位置,$fast$ 指针指向当前待处理元素。
2. 本题要求相同元素最多出现 $2$ 次,并且 $slow - 2$ 是上上次放置了元素的位置。则应该检查 $nums[slow - 2]$ 和当前待处理元素 $nums[fast]$ 是否相同。
1. 如果 $nums[slow - 2] == nums[fast]$ 时,此时必有 $nums[slow - 2] == nums[slow - 1] == nums[fast]$,则当前 $nums[fast]$ 不保留,直接向右移动快指针 $fast$
2. 如果 $nums[slow - 2] \ne nums[fast]$ 时,则保留 $nums[fast]$。将 $nums[fast]$ 赋值给 $nums[slow]$ ,同时将 $slow$ 右移。然后再向右移动快指针 $fast$
3. 这样 $slow$ 指针左边均为处理好的数组元素,而从 $slow$ 指针指向的位置开始, $fast$ 指针左边都为舍弃的重复元素。
4. 遍历结束之后,此时 $slow$ 就是新数组的长度。

### 思路 1:代码

Expand All @@ -66,5 +66,4 @@ class Solution:
### 思路 1:复杂度分析

- **时间复杂度**:$O(n)$。
- **空间复杂度**:$O(1)$。

- **空间复杂度**:$O(1)$。

0 comments on commit 2876ed0

Please sign in to comment.