Skip to content

Commit

Permalink
更新题解列表
Browse files Browse the repository at this point in the history
  • Loading branch information
itcharge committed Sep 15, 2023
1 parent 6dcba19 commit 28dd338
Show file tree
Hide file tree
Showing 17 changed files with 522 additions and 125 deletions.
10 changes: 9 additions & 1 deletion Solutions/0004. 寻找两个正序数组的中位数.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

## 题目大意

**描述**:给定两个正序(从小到大排序)数组 `nums1``nums2`
**描述**:给定两个正序(从小到大排序)数组 $nums1$、$nums2$

**要求**:找出并返回这两个正序数组的中位数。

Expand All @@ -29,6 +29,14 @@
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
```

- 示例 2:

```python
输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
```

## 解题思路

### 思路 1:二分查找
Expand Down
24 changes: 20 additions & 4 deletions Solutions/0074. 搜索二维矩阵.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

## 题目大意

**描述**:给定一个 `m * n` 大小的有序二维矩阵 `matrix`。矩阵中每行元素从左到右升序排列,每列元素从上到下升序排列。再给定一个目标值 `target`
**描述**:给定一个 $m \times n$ 大小的有序二维矩阵 $matrix$。矩阵中每行元素从左到右升序排列,每列元素从上到下升序排列。再给定一个目标值 $target$

**要求**:判断矩阵中是否存在目标值 `target`
**要求**:判断矩阵中是否存在目标值 $target$。

**说明**

Expand All @@ -20,19 +20,30 @@

- 示例 1:

![](https://assets.leetcode.com/uploads/2020/10/05/mat.jpg)

```python
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3
输出:True
```

- 示例 2:

![](https://assets.leetcode-cn.com/aliyun-lc-upload/uploads/2020/11/25/mat2.jpg)

```python
输入:matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13
输出:False
```

## 解题思路

### 思路 1:二分查找

二维矩阵是有序的,可以考虑使用二分搜索来进行查找。

1. 首先二分查找遍历对角线元素,假设对角线元素的坐标为 `(row, col)`。把数组元素按对角线分为右上角部分和左下角部分。
2. 然后对于当前对角线元素右侧第 `row` 行、对角线元素下侧第 `col` 列进行二分查找。
1. 首先二分查找遍历对角线元素,假设对角线元素的坐标为 $(row, col)$。把数组元素按对角线分为右上角部分和左下角部分。
2. 然后对于当前对角线元素右侧第 $row$ 行、对角线元素下侧第 $col$ 列进行二分查找。
1. 如果找到目标,直接返回 `True`
2. 如果找不到目标,则缩小范围,继续查找。
3. 直到所有对角线元素都遍历完,依旧没找到,则返回 `False`
Expand Down Expand Up @@ -100,3 +111,8 @@ class Solution:
return True
return False
```

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

- **时间复杂度**:$O(\log m + \log n)$,其中 $m$、$n$ 分别是矩阵的行数和列数。
- **空间复杂度**:$O(1)$。
58 changes: 45 additions & 13 deletions Solutions/0081. 搜索旋转排序数组 II.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,39 @@

## 题目大意

一个按照升序排列的整数数组 `nums`,在位置的某个下标 `k` 处进行了旋转操作。(例如:`[0, 1, 2, 5, 6, 8]` 可能变为 `[5, 6, 8, 0, 1, 2]`)。
**描述**一个按照升序排列的整数数组 $nums$,在位置的某个下标 $k$ 处进行了旋转操作。(例如:$[0, 1, 2, 5, 6, 8]$ 可能变为 $[5, 6, 8, 0, 1, 2]$)。

现在给定旋转后的数组 `nums` 和一个整数 `target`。要求:编写一个函数来判断给定的 `target` 是否存在与数组中。如果存在则返回 `True`,否则返回 `False`
现在给定旋转后的数组 $nums$ 和一个整数 $target$。

**要求**:编写一个函数来判断给定的 $target$ 是否存在与数组中。如果存在则返回 `True`,否则返回 `False`

**说明**

- $1 \le nums.length \le 5000$。
- $-10^4 \le nums[i] \le 10^4$。
- 题目数据保证 $nums$ 在预先未知的某个下标上进行了旋转。
- $-10^4 \le target \le 10^4$。

**示例**

- 示例 1:

```python
输入:nums = [2,5,6,0,0,1,2], target = 0
输出:true
```

- 示例 2:

```python
输入:nums = [2,5,6,0,0,1,2], target = 3
输出:false
```

## 解题思路

### 思路 1:二分查找

这道题算是「[0033. 搜索旋转排序数组](https://leetcode.cn/problems/search-in-rotated-sorted-array/)」的变形,只不过输出变为了判断。

原本为升序排列的数组 nums 经过「旋转」之后,会有两种情况,第一种就是原先的升序序列,另一种是两段升序的序列。
Expand Down Expand Up @@ -39,20 +66,20 @@

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

然后创建两个指针 leftright,分别指向数组首尾。让后计算出两个指针中间值 mid。将 mid 与两个指针做比较,并考虑与 target 的关系。
然后创建两个指针 $left$、$right$,分别指向数组首尾。让后计算出两个指针中间值 $mid$。将 $mid$ 与两个指针做比较,并考虑与 $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 位置。
- 如果 $nums[mid] > nums[left]$,则 $mid$ 在左半部分(因为右半部分值都比 $nums[left]$ 小)。
- 如果 $nums[mid] \ge target$,并且 $target \ge nums[left]$,则 $target$ 在左半部分,并且在 $mid$ 左侧,此时应将 $right$ 左移到 $mid - 1$ 位置。
- 否则如果 $nums[mid] < 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[left]` 是否等于 `target`,如果等于,则返回 `True`,否则返回 `False`
- 如果 $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$ 位置。
- 最终判断 $nums[left]$ 是否等于 $target$,如果等于,则返回 `True`,否则返回 `False`

## 代码
### 思路 1:代码

```python
class Solution:
Expand Down Expand Up @@ -85,3 +112,8 @@ class Solution:
return nums[left] == target
```

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

- **时间复杂度**:$O(n)$,其中 $n$ 是数组 $nums$ 的长度。最坏情况下数组元素均相等且不为 $target$,我们需要访问所有位置才能得出结果。
- **空间复杂度**:$O(1)$。

10 changes: 5 additions & 5 deletions Solutions/0124. 二叉树中的最大路径和.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@
1. 最大路径和中对应路径穿过根节点。
2. 最大路径和中对应路径不穿过根节点。

如果最大路径和中对应路径穿过根节点,则:$该二叉树的最大路径和 = 左子树中最大贡献值 + 右子树中最大贡献值 + 当前节点值$
如果最大路径和中对应路径穿过根节点,则:**该二叉树的最大路径和 = 左子树中最大贡献值 + 右子树中最大贡献值 + 当前节点值**

而如果最大路径和中对应路径不穿过根节点,则:$该二叉树的最大路径和 = 所有子树中最大路径和$
而如果最大路径和中对应路径不穿过根节点,则:**该二叉树的最大路径和 = 所有子树中最大路径和**

即:$该二叉树的最大路径和 = max(左子树中最大贡献值 + 右子树中最大贡献值 + 当前节点值, \quad 所有子树中最大路径和)$
即:**该二叉树的最大路径和 = max(左子树中最大贡献值 + 右子树中最大贡献值 + 当前节点值所有子树中最大路径和)**

对此我们可以使用深度优先搜索递归遍历二叉树,并在递归遍历的同时,维护一个最大路径和变量 $ans$。

Expand All @@ -60,15 +60,15 @@
计算的结果可能的情况有 $2$ 种:

1. 经过空节点的最大贡献值等于 $0$。
2. 经过非空节点的最大贡献值等于 $当前节点值 + 左右子节点提供的最大贡献值中较大的一个$。如果该贡献值为负数,可以考虑舍弃,即最大贡献值为 $0$。
2. 经过非空节点的最大贡献值等于 **当前节点值 + 左右子节点提供的最大贡献值中较大的一个**。如果该贡献值为负数,可以考虑舍弃,即最大贡献值为 $0$。

在递归时,我们先计算左右子节点的最大贡献值,再更新维护当前最大路径和变量。最终 $ans$ 即为答案。具体步骤如下:

1. 如果根节点 $root$ 为空,则返回 $0$。
2. 递归计算左子树的最大贡献值为 $left\underline{}max$。
3. 递归计算右子树的最大贡献值为 $right\underline{}max$。
4. 更新维护最大路径和变量,即 $self.ans = max \lbrace self.ans, \quad left\underline{}max + right\underline{}max + node.val \rbrace$。
5. 返回以当前节点为根节点,并且经过该节点的最大贡献值。即返回 $当前节点值 + 左右子节点提供的最大贡献值中较大的一个$
5. 返回以当前节点为根节点,并且经过该节点的最大贡献值。即返回 **当前节点值 + 左右子节点提供的最大贡献值中较大的一个**
6. 最终 $self.ans$ 即为答案。

### 思路 1:代码
Expand Down
49 changes: 39 additions & 10 deletions Solutions/0154. 寻找旋转排序数组中的最小值 II.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,41 @@

## 题目大意

给定一个数组 `nums``nums` 是有升序数组经过「旋转」得到的。但是旋转次数未知。数组中可能存在重复元素。
**描述**给定一个数组 $nums$,$nums$ 是有升序数组经过 $1 \sim n$ 次「旋转」得到的。但是旋转次数未知。数组中可能存在重复元素。

要求:找出数组中的最小元素。
**要求**:找出数组中的最小元素。

- 旋转:将数组整体右移。
**说明**

- 旋转:将数组整体右移 $1$ 位。数组 $[a[0], a[1], a[2], ..., a[n-1]]$ 旋转一次的结果为数组 $[a[n-1], a[0], a[1], a[2], ..., a[n-2]]$。
- $n == nums.length$。
- $1 \le n \le 5000$。
- $-5000 \le nums[i] \le 5000$
- $nums$ 原来是一个升序排序的数组,并进行了 $1 \sim n$ 次旋转。

**示例**

- 示例 1:

```python
输入:nums = [1,3,5]
输出:1
```

- 示例 2:

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

## 解题思路

### 思路 1:二分查找

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

第一种的最小值在最左边。第二种最小值在第二段升序序列的第一个元素。
第一种的最小值在最左边。

```
*
Expand All @@ -26,7 +50,7 @@
*
```


第二种最小值在第二段升序序列的第一个元素。

```
*
Expand All @@ -39,13 +63,13 @@

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

创建两个指针 leftright,分别指向数组首尾。让后计算出两个指针中间值 mid。将 mid 与右边界进行比较。
创建两个指针 $left$、$right$,分别指向数组首尾。然后计算出两个指针中间值 $mid$。将 $mid$ 与右边界进行比较。

1. 如果 `nums[mid] > nums[right]`,则最小值不可能在 `mid` 左侧,一定在 `mid` 右侧,则将 `left` 移动到 `mid + 1` 位置,继续查找右侧区间。
2. 如果 `nums[mid] < nums[right]`,则最小值一定在 `mid` 左侧,`right` 移动到 `mid` 位置上,继续查找左侧区间。
3. `nums[mid] == nums[right]`,无法判断在 `mid` 的哪一侧,可以采用 `right = right - 1` 逐步缩小区域。
1. 如果 $nums[mid] > nums[right]$,则最小值不可能在 $mid$ 左侧,一定在 $mid$ 右侧,则将 $left$ 移动到 $mid + 1$ 位置,继续查找右侧区间。
2. 如果 $nums[mid] < nums[right]$,则最小值一定在 $mid$ 左侧,令右边界 $right$ 为 $mid$,继续查找左侧区间。
3. 如果 $nums[mid] == nums[right]$,无法判断在 $mid$ 的哪一侧,可以采用 `right = right - 1` 逐步缩小区域。

## 代码
### 思路 1:代码

```python
class Solution:
Expand All @@ -63,3 +87,8 @@ class Solution:
return nums[left]
```

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

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

8 changes: 4 additions & 4 deletions Solutions/0240. 搜索二维矩阵 II.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@

## 题目大意

**描述**:给定一个 $m \times n$ 大小的有序整数矩阵 `matrix``matrix` 中的每行元素从左到右升序排列,每列元素从上到下升序排列。再给定一个目标值 `target`
**描述**:给定一个 $m \times n$ 大小的有序整数矩阵 $matrix$。$matrix$ 中的每行元素从左到右升序排列,每列元素从上到下升序排列。再给定一个目标值 $target$

**要求**:判断矩阵中是否可以找到 `target`,如果可以找到 `target`,返回 `True`,否则返回 `False`
**要求**:判断矩阵中是否可以找到 $target$,如果可以找到 $target$,返回 `True`,否则返回 `False`

**说明**

Expand Down Expand Up @@ -45,8 +45,8 @@

矩阵是有序的,可以考虑使用二分查找来做。

1. 迭代对角线元素,假设对角线元素的坐标为 `(row, col)`。把数组元素按对角线分为右上角部分和左下角部分。
2. 对于当前对角线元素右侧第 `row` 行、对角线元素下侧第 `col` 列分别进行二分查找。
1. 迭代对角线元素,假设对角线元素的坐标为 $(row, col)$。把数组元素按对角线分为右上角部分和左下角部分。
2. 对于当前对角线元素右侧第 $row$ 行、对角线元素下侧第 $col$ 列分别进行二分查找。
1. 如果找到目标,直接返回 `True`
2. 如果找不到目标,则缩小范围,继续查找。
3. 直到所有对角线元素都遍历完,依旧没找到,则返回 `False`
Expand Down
44 changes: 40 additions & 4 deletions Solutions/0287. 寻找重复数.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,46 @@

## 题目大意

给定一个包含 n+1 个整数的数组 nums,里边包含的值都在 1~n 之间。假设 nums 中只存在一个重复的整数,要求找出这个重复的数
**描述**给定一个包含 $n + 1$ 个整数的数组 $nums$,里边包含的值都在 $1 \sim n$ 之间。可知至少存在一个重复的整数

要求使用空间复杂度为常数级 O(1) ,时间复杂度小于 $O(n^2)$ 的解决方法。
**要求**:假设 $nums$ 中只存在一个重复的整数,要求找出这个重复的数。

**说明**

- $1 \le n \le 10^5$。
- $nums.length == n + 1$。
- $1 \le nums[i] \le n$。
- 要求使用空间复杂度为常数级 $O(1)$,时间复杂度小于 $O(n^2)$ 的解决方法。

**示例**

- 示例 1:

```python
输入:nums = [1,3,4,2,2]
输出:2
```

- 示例 2:

```python
输入:nums = [3,1,3,4,2]
输出:3
```

## 解题思路

利用二分查找的思想。用两个指针 left,right。left 指向 1,right 指向 n。将区间 [1, n] 分为 [left, mid][mid + 1, right] 。对于中间数 mid,统计 nums 中小于等于 mid 的数个数 cnt。如果 cnt 小于等于 mid,则重复数一定不会出现在左侧区间,那么从右侧区间开始搜索。若 cut 大于 mid,则重复数出现在左侧区间,则从左侧区间开始搜索。
### 思路 1:二分查找

利用二分查找的思想。

## 代码
1. 使用两个指针 $left$,$right$。$left$ 指向 $1$,$right$ 指向 $n$。
2. 将区间 $[1, n]$ 分为 $[left, mid]$ 和 $[mid + 1, right]$。
3. 对于中间数 $mid$,统计 $nums$ 中小于等于 $mid$ 的数个数 $cnt$。
4. 如果 $cnt \le mid$,则重复数一定不会出现在左侧区间,那么从右侧区间开始搜索。
5. 如果 $cut > mid$,则重复数出现在左侧区间,则从左侧区间开始搜索。

### 思路 1:代码

```python
class Solution:
Expand All @@ -36,3 +67,8 @@ class Solution:
return left
```

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

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

Loading

0 comments on commit 28dd338

Please sign in to comment.