diff --git a/Contents/00.Introduction/02.Algorithm-Complexity.md b/Contents/00.Introduction/02.Algorithm-Complexity.md index 8b8b54f3..02744978 100644 --- a/Contents/00.Introduction/02.Algorithm-Complexity.md +++ b/Contents/00.Introduction/02.Algorithm-Complexity.md @@ -72,14 +72,14 @@ def algorithm(n): 例如:$T(n) = 3n^2 + 4n + 5 = \Theta(n^2),ドル可以找到 $c_1 = 1,ドル$c_2 = 12,ドル$n_0 = 1,ドル使得对于所有 $n \ge 1,ドル都有 $n^2 \le 3n^2 + 4n + 5 \le 12n^2$。 -#### 2.2.1 $O$ 渐进上界符号 +#### 2.2.2 $O$ 渐进上界符号 > **$O$ 渐进上界符号**: > 对于函数 $f(n)$ 和 $g(n),ドル$f(n) = O(g(n))$。存在常量 $c,ドル$n_0,ドル使得当 $n> n_0$ 时,有 0ドル \le f(n) \le c \cdot g(n)$。 $\Theta$ 符号渐进地给出了一个函数的上界和下界,如果我们只知道一个函数的上界,可以使用 $O$ 符号。 -#### 2.2.1 $\Omega$ 渐进下界符号 +#### 2.2.3 $\Omega$ 渐进下界符号 > **$\Omega$ 渐进下界符号**: > 对于函数 $f(n)$ 和 $g(n),ドル$f(n) = \Omega(g(n))$。存在常量 $c,ドル$n_0,ドル使得当 $n> n_0$ 时,有 0ドル \le c \cdot g(n) \le f(n)$。 diff --git "a/Solutions/0506. 347円233円270円345円257円271円345円220円215円346円254円241円.md" "b/Solutions/0506. 347円233円270円345円257円271円345円220円215円346円254円241円.md" index aa2d7591..e9a2b64a 100644 --- "a/Solutions/0506. 347円233円270円345円257円271円345円220円215円346円254円241円.md" +++ "b/Solutions/0506. 347円233円270円345円257円271円345円220円215円346円254円241円.md" @@ -5,15 +5,38 @@ ## 题目大意 -给出 `n` 名运动员的成绩,用数组 `score` 表示。 +**描述**:给定一个长度为 `n` 的数组 `score`。其中 `score[i]` 表示第 `i` 名运动员在比赛中的成绩。所有成绩互不相同。 -要求:找出他们的相对名次,并授予前三名对应的奖牌。前三名运动员将会被分别授予「金牌」,「银牌」和「铜牌」(`Gold Medal`, `Silver Medal`, `Bronze Medal`)。 +**要求**:找出他们的相对名次,并授予前三名对应的奖牌。前三名运动员将会被分别授予「金牌(`Gold Medal`)」,「银牌(`Silver Medal`)」和「铜牌(`Bronze Medal`)」。 + +**说明**: + +- $n == score.length$。 +- 1ドル \le n \le 10^4$。 +- 0ドル \le score[i] \le 10^6$。 +- `score` 中的所有值互不相同。 + +**示例**: + +```Python +输入:score = [5,4,3,2,1] +输出:["Gold Medal","Silver Medal","Bronze Medal","4","5"] +解释:名次为 [1st, 2nd, 3rd, 4th, 5th] 。 + + +输入:score = [10,3,8,9,4] +输出:["Gold Medal","5","Bronze Medal","Silver Medal","4"] +解释:名次为 [1st, 5th, 3rd, 2nd, 4th] 。 +``` ## 解题思路 -先对数组 `score` 进行排序,再将对应前三个位置上的元素替换成对应的字符串:`Gold Medal`, `Silver Medal`, `Bronze Medal`。 +### 思路 1:排序 -## 代码 +1. 先对数组 `score` 进行排序。 +2. 再将对应前三个位置上的元素替换成对应的字符串:`Gold Medal`, `Silver Medal`, `Bronze Medal`。 + +### 思路 1:代码 ```Python class Solution: @@ -52,3 +75,7 @@ class Solution: return res ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n \times \log_2n)$。因为采用了时间复杂度为 $O(n \times \log_2n)$ 的希尔排序。 +- **空间复杂度**:$O(n)$。 diff --git "a/Solutions/0704. 344円272円214円345円210円206円346円237円245円346円211円276円.md" "b/Solutions/0704. 344円272円214円345円210円206円346円237円245円346円211円276円.md" index 7e018827..911f649a 100644 --- "a/Solutions/0704. 344円272円214円345円210円206円346円237円245円346円211円276円.md" +++ "b/Solutions/0704. 344円272円214円345円210円206円346円237円245円346円211円276円.md" @@ -5,38 +5,60 @@ ## 题目大意 -给定一个升序的数组 nums,和一个目标值 target,返回 target 在数组中的位置,如果找不到,则返回 -1。 +**描述**:给定一个升序的数组 `nums`,和一个目标值 `target`。 -## 解题思路 +**要求**:返回 `target` 在数组中的位置,如果找不到,则返回 -1。 + +**说明**: -纯粹考察二分查找。 +- 你可以假设 `nums` 中的所有元素是不重复的。 +- `n` 将在 `[1, 10000]`之间。 +- `nums` 的每个元素都将在 `[-9999, 9999]`之间。 -算法基本原理: +**示例**: + +```Python +输入: nums = [-1,0,3,5,9,12], target = 9 +输出: 4 +解释: 9 出现在 nums 中并且下标为 4 -设定左右节点为数组两端。不断判断两个节点中心位置与目标值的大小。 + +输入: nums = [-1,0,3,5,9,12], target = 2 +输出: -1 +解释: 2 不存在 nums 中因此返回 -1 +``` + +## 解题思路 + +### 思路 1:二分查找。 + +设定左右节点为数组两端。不断判断两个节点中心位置与目标值的大小: - 如果中心位置与目标值相等,则返回中心位置。 -- 如果中心位置小于目标值,则将左节点设置为中心位置+1,然后继续在右侧搜索。 -- 如果中心位置大于目标值,则将右节点设置为中心位置-1,然后继续在左侧搜索。 -## 代码 +- 如果中心位置小于目标值,则将左节点设置为中心位置加 `1`,然后继续在右侧搜索。 +- 如果中心位置大于目标值,则将右节点设置为中心位置减 `1`,然后继续在左侧搜索。 + +### 思路 1:代码 ```Python class Solution: def search(self, nums: List[int], target: int) -> int: - left = 0 - right = len(nums)-1 - ans = -1 + left, right = 0, len(nums) - 1 + while left <= right: - mid = (left+right)//2 + mid = (left + right) // 2 if nums[mid] == target: - ans = mid - left = mid+1 - return ans + return mid if nums[mid] < target: - left = mid+1 + left = mid + 1 else: - right = mid-1 - return ans + right = mid - 1 + return -1 ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(\log_2n)$。 +- **空间复杂度**:$O(1)$。 + diff --git "a/Solutions/345円211円221円346円214円207円 Offer 51. 346円225円260円347円273円204円344円270円255円347円232円204円351円200円206円345円272円217円345円257円271円.md" "b/Solutions/345円211円221円346円214円207円 Offer 51. 346円225円260円347円273円204円344円270円255円347円232円204円351円200円206円345円272円217円345円257円271円.md" index 65343f8b..e95d0f64 100644 --- "a/Solutions/345円211円221円346円214円207円 Offer 51. 346円225円260円347円273円204円344円270円255円347円232円204円351円200円206円345円272円217円345円257円271円.md" +++ "b/Solutions/345円211円221円346円214円207円 Offer 51. 346円225円260円347円273円204円344円270円255円347円232円204円351円200円206円345円272円217円345円257円271円.md" @@ -5,17 +5,110 @@ ## 题目大意 -给定一个数组 `nums`。 +**描述**:给定一个数组 `nums`。 -要求:计算出数组中的逆序对的总数。 +**要求**:计算出数组中的逆序对的总数。 + +**说明**: + +- **逆序对**:在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。 +- 0ドル \le nums.length \le 50000$。 + +**示例**: + +```Python +输入: [7,5,6,4] +输出: 5 +``` ## 解题思路 -可以用树状数组解决。 +### 思路 1:归并排序 + +归并排序主要分为:「分解过程」和「合并过程」。其中「合并过程」实质上是两个有序数组的合并过程。 -数组 `tree[i]` 表示数字 `i` 是否在序列中出现过,如果数字 `i` 已经存在于序列中,`tree[i] = 1`,否则 `tree[i] = 0`。按序列从左到右将值为 `nums[i]` 的元素当作下标为`nums[i]`,赋值为 `1` 插入树状数组里,这时,比 `nums[i]` 大的数个数就是 `i + 1 - query(a)`。将全部结果累加起来就是逆序数了。 + -## 代码 +每当遇到 左子数组当前元素> 右子树组当前元素时,意味着「左子数组从当前元素开始,一直到左子数组末尾元素」与「右子树组当前元素」构成了若干个逆序对。 + +比如上图中的左子数组 `[0, 3, 5, 7]` 与右子树组 `[1, 4, 6, 8]`,遇到左子数组中元素 `3` 大于右子树组中元素 `1`。则左子数组从 `3` 开始,经过 `5` 一直到 `7`,与右子数组当前元素 `1` 都构成了逆序对。即 `[3, 1]`、`[5, 1]`、`[7, 1]` 都构成了逆序对。 + +因此,我们可以在合并两个有序数组的时候计算逆序对。具体做法如下: + +1. 使用全局变量 `cnt` 来存储逆序对的个数。然后进行归并排序。 +2. **分割过程**:先递归地将当前序列平均分成两半,直到子序列长度为 `1`。 + 1. 找到序列中心位置 `mid`,从中心位置将序列分成左右两个子序列 `left_arr`、`right_arr`。 + 2. 对左右两个子序列 `left_arr`、`right_arr` 分别进行递归分割。 + 3. 最终将数组分割为 `n` 个长度均为 `1` 的有序子序列。 +3. **归并过程**:从长度为 `1` 的有序子序列开始,依次进行两两归并,直到合并成一个长度为 `n` 的有序序列。 + 1. 使用数组变量 `arr` 存放归并后的有序数组。 + 2. 使用两个指针 `left_i`、`right_i` 分别指向两个有序子序列 `left_arr`、`right_arr` 的开始位置。 + 3. 比较两个指针指向的元素: + 1. 如果 `left_arr[left_i] <= right_arr[right_i]`,则将 `left_arr[left_i]` 存入到结果数组 `arr` 中,并将指针移动到下一位置。 + 2. 如果 `left_arr[left_i]> right_arr[right_i]`,则 **记录当前左子序列中元素与当前右子序列元素所形成的逆序对的个数,并累加到 `cnt` 中,即 `self.cnt += len(left_arr) - left_i`**,然后将 `right_arr[right_i]` 存入到结果数组 `arr` 中,并将指针移动到下一位置。 + 4. 重复步骤 `3`,直到某一指针到达子序列末尾。 + 5. 将另一个子序列中的剩余元素存入到结果数组 `arr` 中。 + 6. 返回归并后的有序数组 `arr`。 +4. 返回数组中的逆序对的总数,即 `self.cnt`。 + +### 思路 1:代码 + +```Python +class Solution: + cnt = 0 + def merge(self, left_arr, right_arr): # 归并过程 + arr = [] + left_i, right_i = 0, 0 + while left_i < len(left_arr) and right_i < len(right_arr): + # 将两个有序子序列中较小元素依次插入到结果数组中 + if left_arr[left_i] <= right_arr[right_i]: + arr.append(left_arr[left_i]) + left_i += 1 + else: + self.cnt += len(left_arr) - left_i + arr.append(right_arr[right_i]) + right_i += 1 + + while left_i < len(left_arr): + # 如果左子序列有剩余元素,则将其插入到结果数组中 + arr.append(left_arr[left_i]) + left_i += 1 + + while right_i < len(right_arr): + # 如果右子序列有剩余元素,则将其插入到结果数组中 + arr.append(right_arr[right_i]) + right_i += 1 + + return arr # 返回排好序的结果数组 + + def mergeSort(self, arr): # 分割过程 + if len(arr) <= 1: # 数组元素个数小于等于 1 时,直接返回原数组 + return arr + + mid = len(arr) // 2 # 将数组从中间位置分为左右两个数组。 + left_arr = self.mergeSort(arr[0: mid]) # 递归将左子序列进行分割和排序 + right_arr = self.mergeSort(arr[mid:]) # 递归将右子序列进行分割和排序 + return self.merge(left_arr, right_arr) # 把当前序列组中有序子序列逐层向上,进行两两合并。 + + def reversePairs(self, nums: List[int]) -> int: + self.cnt = 0 + self.mergeSort(nums) + return self.cnt +``` + +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n \times \log_2n)$。 +- **空间复杂度**:$O(n)$。 + +### 思路 2:树状数组 + +数组 `tree[i]` 表示数字 `i` 是否在序列中出现过,如果数字 `i` 已经存在于序列中,`tree[i] = 1`,否则 `tree[i] = 0`。 + +1. 按序列从左到右将值为 `nums[i]` 的元素当作下标为`nums[i]`,赋值为 `1` 插入树状数组里,这时,比 `nums[i]` 大的数个数就是 `i + 1 - query(a)`。 +2. 将全部结果累加起来就是逆序数了。 + +### 思路 2:代码 ```Python import bisect @@ -56,3 +149,8 @@ class Solution: return ans ``` +### 思路 2:复杂度分析 + +- **时间复杂度**:$O(n \times \log_2n)$。 +- **空间复杂度**:$O(n)$。 + diff --git "a/Solutions/351円235円242円350円257円225円351円242円230円 10.01. 345円220円210円345円271円266円346円216円222円345円272円217円347円232円204円346円225円260円347円273円204円.md" "b/Solutions/351円235円242円350円257円225円351円242円230円 10.01. 345円220円210円345円271円266円346円216円222円345円272円217円347円232円204円346円225円260円347円273円204円.md" index cf23fd3c..0e3e89e2 100644 --- "a/Solutions/351円235円242円350円257円225円351円242円230円 10.01. 345円220円210円345円271円266円346円216円222円345円272円217円347円232円204円346円225円260円347円273円204円.md" +++ "b/Solutions/351円235円242円350円257円225円351円242円230円 10.01. 345円220円210円345円271円266円346円216円222円345円272円217円347円232円204円346円225円260円347円273円204円.md" @@ -5,17 +5,34 @@ ## 题目大意 -给定两个排序后的数组 `A` 和 `B`,以及 `A` 的元素数量 `m` 和 `B` 的元素数量 `n`。 `A` 的末端有足够的缓冲空间容纳 `B`。 -要求:编写一个方法,将 `B` 合并入 `A` 并排序。 +**描述**:给定两个排序后的数组 `A` 和 `B`,以及 `A` 的元素数量 `m` 和 `B` 的元素数量 `n`。 `A` 的末端有足够的缓冲空间容纳 `B`。 +**要求**:编写一个方法,将 `B` 合并入 `A` 并排序。 + +**说明**: + +- $A.length == n + m$。 + +**示例**: + +```Python +输入: +A = [1,2,3,0,0,0], m = 3 +B = [2,5,6], n = 3 + +输出: [1,2,2,3,5,6] +``` ## 解题思路 -双指针,归并排序。 +### 思路 1:归并排序 + +可以利用归并排序算法的归并步骤思路。 -使用两个指针分别表示`A`、`B` 正在处理的元素下标。对 `A`、`B` 进行归并操作,将结果存入新数组中。归并之后,再将所有元素赋值到数组 `A` 中。 +1. 使用两个指针分别表示`A`、`B` 正在处理的元素下标。 +2. 对 `A`、`B` 进行归并操作,将结果存入新数组中。归并之后,再将所有元素赋值到数组 `A` 中。 -## 代码 +### 思路 1:代码 ```Python class Solution: @@ -42,3 +59,8 @@ class Solution: A[i] = arr[i] ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(m + n)$。 +- **空间复杂度**:$O(m + n)$。 +