diff --git "a/Solutions/0567. \345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.md" "b/Solutions/0567. \345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.md" index bf3ac0e9..752a1525 100644 --- "a/Solutions/0567. \345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.md" +++ "b/Solutions/0567. \345\255\227\347\254\246\344\270\262\347\232\204\346\216\222\345\210\227.md" @@ -9,26 +9,50 @@ ## 题目大意 -给定两个字符串 `s1` 和 `s2` 。 +**描述**:给定两个字符串 $s1$ 和 $s2$ 。 -要求:判断 `s2` 是否包含 `s1` 的排列。如果包含,返回 `True`;否则,返回 `False`。 +**要求**:判断 $s2$ 是否包含 $s1$ 的排列。如果包含,返回 $True$;否则,返回 $False$。 + +**说明**: + +- $1 \le s1.length, s2.length \le 10^4$。 +- $s1$ 和 $s2$ 仅包含小写字母。 + +**示例**: + +- 示例 1: + +```python +输入:s1 = "ab" s2 = "eidbaooo" +输出:true +解释:s2 包含 s1 的排列之一 ("ba"). +``` + +- 示例 2: + +```python +输入:s1= "ab" s2 = "eidboaoo" +输出:False +``` ## 解题思路 -题目要求判断 `s2` 是否包含 `s1` 的排列,则 `s2` 的子串长度等于 `s1` 的长度。我们可以维护一个长度为字符串 `s1` 长度的固定长度的滑动窗口。 +### 思路 1:滑动窗口 -先统计出字符串 `s1` 中各个字符的数量,我们用 `s1_count` 来表示。这个过程可以用字典、数组来实现,也可以直接用 `collections.Counter()` 实现。再统计 `s2` 对应窗口内的字符数量 `window_count`,然后不断向右滑动,然后进行比较。如果对应字符数量相同,则返回 `True`,否则继续滑动。直到末尾时,返回 `False`。整个解题步骤具体如下: +题目要求判断 $s2$ 是否包含 $s1$ 的排列,则 $s2$ 的子串长度等于 $s1$ 的长度。我们可以维护一个长度为字符串 $s1$ 长度的固定长度的滑动窗口。 -1. `s1_count` 用来统计 `s1` 中各个字符数量。`window_count` 用来维护窗口中 `s2` 对应子串的各个字符数量。`window_size` 表示固定窗口的长度,值为 `len(s1)`。 -2. 先统计出 `s1` 中各个字符数量。 -3. `left` 、`right` 都指向序列的第一个元素,即:`left = 0`,`right = 0`。 -4. 向右移动 `right`,先将 `len(s1)` 个元素填入窗口中。 -5. 当窗口元素个数为 `window_size` 时,即:`right - left + 1 >= window_size` 时,判断窗口内各个字符数量 `window_count` 是否等于 `s1 ` 中各个字符数量 `s1_count`。 - 1. 如果等于,直接返回 `True`。 - 2. 如果不等于,则向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 `window_size`。 -6. 重复 4 ~ 5 步,直到 `right` 到达数组末尾。返回 `False`。 +先统计出字符串 $s1$ 中各个字符的数量,我们用 $s1\underline{}count$ 来表示。这个过程可以用字典、数组来实现,也可以直接用 `collections.Counter()` 实现。再统计 $s2$ 对应窗口内的字符数量 $window\underline{}count$,然后不断向右滑动,然后进行比较。如果对应字符数量相同,则返回 $True$,否则继续滑动。直到末尾时,返回 $False$。整个解题步骤具体如下: -## 代码 +1. $s1\underline{}count$ 用来统计 $s1$ 中各个字符数量。$window\underline{}count$ 用来维护窗口中 $s2$ 对应子串的各个字符数量。$window\underline{}size$ 表示固定窗口的长度,值为 $len(s1)$。 +2. 先统计出 $s1$ 中各个字符数量。 +3. $left$ 、$right$ 都指向序列的第一个元素,即:`left = 0`,`right = 0`。 +4. 向右移动 $right$,先将 $len(s1)$ 个元素填入窗口中。 +5. 当窗口元素个数为 $window\underline{}size$ 时,即:$right - left + 1 \ge window\underline{}size$ 时,判断窗口内各个字符数量 $window\underline{}count$ 是否等于 $s1 $ 中各个字符数量 $s1\underline{}count$。 + 1. 如果等于,直接返回 $True$。 + 2. 如果不等于,则向右移动 $left$,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 $window\underline{}size$。 +6. 重复 $4 \sim 5$ 步,直到 $right$ 到达数组末尾。返回 $False$。 + +### 思路 1:代码 ```python import collections @@ -54,3 +78,8 @@ class Solution: return False ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n + m + |\sum|)$,其中 $n$、$m$ 分别是字符串 $s1$、$s2$ 的长度,$\sum$ 是字符集,本题中 $|\sum| = 26$。 +- **空间复杂度**:$O(|\sum|)$。 + diff --git "a/Solutions/0844. \346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.md" "b/Solutions/0844. \346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.md" index d385b6b4..19311b32 100644 --- "a/Solutions/0844. \346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.md" +++ "b/Solutions/0844. \346\257\224\350\276\203\345\220\253\351\200\200\346\240\274\347\232\204\345\255\227\347\254\246\344\270\262.md" @@ -9,46 +9,47 @@ ## 题目大意 -给定 `s` 和 `t` 两个字符串。字符串中的 `#` 代表退格字符。 +**描述**:给定 $s$ 和 $t$ 两个字符串。字符串中的 `#` 代表退格字符。 -要求:当它们分别被输入到空白的文本编辑器后,判断二者是否相等。如果相等,返回 `True`;否则,返回 `False`。 +**要求**:当它们分别被输入到空白的文本编辑器后,判断二者是否相等。如果相等,返回 $True$;否则,返回 $False$。 -注意:如果对空文本输入退格字符,文本继续为空。 +**说明**: + +- 如果对空文本输入退格字符,文本继续为空。 +- $1 \le s.length, t.length \le 200$。 +- $s$ 和 $t$ 只含有小写字母以及字符 `#`。 + +**示例**: + +- 示例 1: + +```python +输入:s = "ab#c", t = "ad#c" +输出:true +解释:s 和 t 都会变成 "ac"。 +``` + +- 示例 2: + +```python +输入:s = "ab##", t = "c#d#" +输出:true +解释:s 和 t 都会变成 ""。 +``` ## 解题思路 这道题的第一个思路是用栈,第二个思路是使用分离双指针。 -思路一:栈。 +### 思路 1:栈 - 定义一个构建方法,用来将含有退格字符串构建为删除退格的字符串。构建方法如下。 - 使用一个栈存放删除退格的字符串。 - 遍历字符串,如果遇到的字符不是 `#`,则将其插入到栈中。 - 如果遇到的字符是 `#`,且当前栈不为空,则将当前栈顶元素弹出。 -- 分别使用构建方法处理字符串 `s` 和 `t`,如果处理完的字符串 `s` 和 `t` 相等,则返回 `True`,否则返回 `False`。 - -思路二:分离双指针。 +- 分别使用构建方法处理字符串 $s$ 和 $t$,如果处理完的字符串 $s$ 和 $t$ 相等,则返回 $True$,否则返回 $False$。 -由于 `#` 会消除左侧字符,而不会影响右侧字符,所以我们选择从字符串尾端遍历 `s`、`t` 字符串。具体做法如下: - -- 使用分离双指针 `left_1`、`left_2`。`left_1` 指向字符串 `s` 末尾,`left_2` 指向字符串 `t` 末尾。使用 `sign_1`、`sign_2` 标记字符串 `s`、`t` 中当前退格字符个数。 -- 从后到前遍历字符串 `s`、`t`。 - - 先来循环处理字符串 `s` 尾端 `#` 的影响,具体如下: - - 如果当前字符是 `#`,则更新 `s` 当前退格字符个数,即 `sign_1 += 1`。同时将 `left_1` 左移。 - - 如果 `s` 当前退格字符个数大于 `0`,则退格数减一,即 `sign_1 -= 1`。同时将 `left_1` 左移。 - - 如果 `s` 当前为普通字符,则跳出循环。 - - 同理再来处理字符串 `t` 尾端 `#` 的影响,具体如下: - - 如果当前字符是 `#`,则更新 `t` 当前退格字符个数,即 `sign_2 += 1`。同时将 `left_2` 左移。 - - 如果 `t` 当前退格字符个数大于 `0`,则退格数减一,即 `sign_2 -= 1`。同时将 `left_2` 左移。 - - 如果 `t` 当前为普通字符,则跳出循环。 - - 处理完,如果两个字符串为空,则说明匹配,直接返回 `True`。 - - 再先排除长度不匹配的情况,直接返回 `False`。 - - 最后判断 `s[left_1]` 是否等于 `s[left_2]`。不等于则直接返回 `False`,等于则令 `left_1`、`left_2` 左移,继续遍历。 -- 遍历完没有出现不匹配的情况,则返回 `True`。 - -## 代码 - -- 思路一: +### 思路 1:代码 ```python class Solution: @@ -65,7 +66,31 @@ class Solution: return self.build(s) == self.build(t) ``` -- 思路二: +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n + m)$,其中 $n$ 和 $m$ 分别为字符串 $s$、$t$ 的长度。 +- **空间复杂度**:$O(n + m)$。 + +### 思路 2:分离双指针 + +由于 `#` 会消除左侧字符,而不会影响右侧字符,所以我们选择从字符串尾端遍历 $s$、$t$ 字符串。具体做法如下: + +- 使用分离双指针 $left\underline{}1$、$left\underline{}2$。$left\underline{}1$ 指向字符串 $s$ 末尾,$left\underline{}2$ 指向字符串 $t$ 末尾。使用 $sign\underline{}1$、$sign\underline{}2$ 标记字符串 $s$、$t$ 中当前退格字符个数。 +- 从后到前遍历字符串 $s$、$t$。 + - 先来循环处理字符串 $s$ 尾端 `#` 的影响,具体如下: + - 如果当前字符是 `#`,则更新 $s$ 当前退格字符个数,即 `sign_1 += 1`。同时将 $left\underline{}1$ 左移。 + - 如果 $s$ 当前退格字符个数大于 $0$,则退格数减一,即 `sign_1 -= 1`。同时将 $left\underline{}1$ 左移。 + - 如果 $s$ 当前为普通字符,则跳出循环。 + - 同理再来处理字符串 $t$ 尾端 `#` 的影响,具体如下: + - 如果当前字符是 `#`,则更新 $t$ 当前退格字符个数,即 `sign_2 += 1`。同时将 $left\underline{}2$ 左移。 + - 如果 $t$ 当前退格字符个数大于 $0$,则退格数减一,即 `sign_2 -= 1`。同时将 $left\underline{}2$ 左移。 + - 如果 $t$ 当前为普通字符,则跳出循环。 + - 处理完,如果两个字符串为空,则说明匹配,直接返回 $True$。 + - 再先排除长度不匹配的情况,直接返回 $False$。 + - 最后判断 $s[left\underline{}1]$ 是否等于 $s[left\underline{}2]$。不等于则直接返回 $False$,等于则令 $left\underline{}1$、$left\underline{}2$ 左移,继续遍历。 +- 遍历完没有出现不匹配的情况,则返回 $True$。 + +### 思路 2:代码 ```python class Solution: @@ -108,3 +133,8 @@ class Solution: return True ``` +### 思路 2:复杂度分析 + +- **时间复杂度**:$O(n + m)$,其中 $n$ 和 $m$ 分别为字符串 $s$、$t$ 的长度。 +- **空间复杂度**:$O(1)$。 + diff --git "a/Solutions/1052. \347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" "b/Solutions/1052. \347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" index 3b5d86bb..1e1a2072 100644 --- "a/Solutions/1052. \347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" +++ "b/Solutions/1052. \347\210\261\347\224\237\346\260\224\347\232\204\344\271\246\345\272\227\350\200\201\346\235\277.md" @@ -9,28 +9,55 @@ ## 题目大意 -书店老板有一家店打算试营业 `len(customers)` 分钟。每一分钟都有一些顾客 `customers[i]` 会进入书店,这些顾客会在这一分钟结束后离开。 +**描述**:书店老板有一家店打算试营业 $len(customers)$ 分钟。每一分钟都有一些顾客 $customers[i]$ 会进入书店,这些顾客会在这一分钟结束后离开。 -在某些时候,书店老板会生气。如果书店老板在第 `i` 分钟生气,则 `grumpy[i] = 1`,如果第 `i` 分钟不生气,则 `grumpy[i] = 0`。当书店老板生气时,这一分钟的顾客会不满意。当书店老板不生气时,这一分钟的顾客是满意的。 +在某些时候,书店老板会生气。如果书店老板在第 $i$ 分钟生气,则 `grumpy[i] = 1`,如果第 $i$ 分钟不生气,则 `grumpy[i] = 0`。当书店老板生气时,这一分钟的顾客会不满意。当书店老板不生气时,这一分钟的顾客是满意的。 -假设老板知道一个秘密技巧,能保证自己连续 `minutes` 分钟不生气,但只能使用一次。 +假设老板知道一个秘密技巧,能保证自己连续 $minutes$ 分钟不生气,但只能使用一次。 -现在给定代表每分钟进入书店的顾客数量的数组 `customes`,和代表老板生气状态的数组 `grumpy`,以及老板保证连续不生气的分钟数 `minutes`。 +现在给定代表每分钟进入书店的顾客数量的数组 $customes$,和代表老板生气状态的数组 $grumpy$,以及老板保证连续不生气的分钟数 $minutes$。 -要求:计算出试营业下来,最多有多少客户能够感到满意。 +**要求**:计算出试营业下来,最多有多少客户能够感到满意。 + +**说明**: + +- $n == customers.length == grumpy.length$。 +- $1 \le minutes \le n \le 2 \times 10^4$。 +- $0 \le customers[i] \le 1000$。 +- $grumpy[i] == 0 \text{ or } 1$。 + +**示例**: + +- 示例 1: + +```python +输入:customers = [1,0,1,2,1,1,7,5], grumpy = [0,1,0,1,0,1,0,1], minutes = 3 +输出:16 +解释:书店老板在最后 3 分钟保持冷静。 +感到满意的最大客户数量 = 1 + 1 + 1 + 1 + 7 + 5 = 16. +``` + +- 示例 2: + +```python +输入:customers = [1], grumpy = [0], minutes = 1 +输出:1 +``` ## 解题思路 -固定长度的滑动窗口题目。我们可以维护一个窗口大小为 `minutes` 的滑动窗口。使用 `window_count` 记录当前窗口内生气的顾客人数。然后滑动求出窗口中最大顾客数,然后累加上老板未生气时的顾客数,就是答案。具体做法如下: +### 思路 1:滑动窗口 -1. `ans` 用来维护答案数目。`window_count` 用来维护窗口中生气的顾客人数。 -2. `left` 、`right` 都指向序列的第一个元素,即:`left = 0`,`right = 0`。 -3. 如果书店老板生气,则将这一分钟的顾客数量加入到 `window_count` 中,然后向右移动 `right`。 -4. 当窗口元素个数大于 `minutes` 时,即:`right - left + 1 > count` 时,如果最左侧边界老板处于生气状态,则向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为小于 `minutes`。 -5. 重复 3 ~ 4 步,直到 `right` 到达数组末尾。 +固定长度的滑动窗口题目。我们可以维护一个窗口大小为 $minutes$ 的滑动窗口。使用 $window_count$ 记录当前窗口内生气的顾客人数。然后滑动求出窗口中最大顾客数,然后累加上老板未生气时的顾客数,就是答案。具体做法如下: + +1. $ans$ 用来维护答案数目。$window\underline{}count$ 用来维护窗口中生气的顾客人数。 +2. $left$ 、$right$ 都指向序列的第一个元素,即:`left = 0`,`right = 0`。 +3. 如果书店老板生气,则将这一分钟的顾客数量加入到 $window\underline{}count$ 中,然后向右移动 $right$。 +4. 当窗口元素个数大于 $minutes$ 时,即:$right - left + 1 > count$ 时,如果最左侧边界老板处于生气状态,则向右移动 $left$,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为小于 $minutes$。 +5. 重复 $3 \sim 4$ 步,直到 $right$ 到达数组末尾。 6. 然后累加上老板未生气时的顾客数,最后输出答案。 -## 代码 +### 思路 1:代码 ```python class Solution: @@ -58,3 +85,8 @@ class Solution: return ans ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$,其中 $n$ 为数组 $coustomer$、$grumpy$ 的长度。 +- **空间复杂度**:$O(1)$。 + diff --git "a/Solutions/1100. \351\225\277\345\272\246\344\270\272 K \347\232\204\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\345\255\220\344\270\262.md" "b/Solutions/1100. \351\225\277\345\272\246\344\270\272 K \347\232\204\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\345\255\220\344\270\262.md" index c5385b70..917f3e11 100644 --- "a/Solutions/1100. \351\225\277\345\272\246\344\270\272 K \347\232\204\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\345\255\220\344\270\262.md" +++ "b/Solutions/1100. \351\225\277\345\272\246\344\270\272 K \347\232\204\346\227\240\351\207\215\345\244\215\345\255\227\347\254\246\345\255\220\344\270\262.md" @@ -9,12 +9,40 @@ ## 题目大意 -给定一个字符串 `s`。 +**描述**:给定一个字符串 `s`。 -要求:找出所有长度为 `k` 且不含重复字符的子串,返回全部满足要求的子串的数目。 +**要求**:找出所有长度为 `k` 且不含重复字符的子串,返回全部满足要求的子串的数目。 + +**说明**: + +- $1 \le s.length \le 10^4$。 +- $s$ 中的所有字符均为小写英文字母。 +- $1 <= k <= 10^4$。 + +**示例**: + +- 示例 1: + +```python +输入:s = "havefunonleetcode", k = 5 +输出:6 +解释: +这里有 6 个满足题意的子串,分别是:'havef','avefu','vefun','efuno','etcod','tcode'。 +``` + +- 示例 2: + +```python +输入:s = "home", K = 5 +输出:0 +解释: +注意:k 可能会大于 s 的长度。在这种情况下,就无法找到任何长度为 k 的子串。 +``` ## 解题思路 +### 思路 1:滑动窗口 + 固定长度滑动窗口的题目。维护一个长度为 `k` 的滑动窗口。用 `window_count` 来表示窗口内所有字符个数。可以用字典、数组来实现,也可以直接用 `collections.Counter()` 实现。然后不断向右滑动,然后进行比较。如果窗口内字符无重复,则答案数目 + 1。然后继续滑动。直到末尾时。整个解题步骤具体如下: 1. `window_count` 用来维护窗口中 `2` 对应子串的各个字符数量。 @@ -25,7 +53,7 @@ 2. 如果不等于,则向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 `k`。 5. 重复 3 ~ 4 步,直到 `right` 到达数组末尾。返回答案。 -## 代码 +### 思路 1:代码 ```python import collections @@ -52,3 +80,8 @@ class Solution: return ans ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$,其中 $n$ 为字符串 $s$ 的长度。 +- **空间复杂度**:$O(|\sum|)$,其中 $\sum$ 是字符集。 + diff --git "a/Solutions/1229. \345\256\211\346\216\222\344\274\232\350\256\256\346\227\245\347\250\213.md" "b/Solutions/1229. \345\256\211\346\216\222\344\274\232\350\256\256\346\227\245\347\250\213.md" index 7ded99f0..94cd6e0a 100644 --- "a/Solutions/1229. \345\256\211\346\216\222\344\274\232\350\256\256\346\227\245\347\250\213.md" +++ "b/Solutions/1229. \345\256\211\346\216\222\344\274\232\350\256\256\346\227\245\347\250\213.md" @@ -9,28 +9,54 @@ ## 题目大意 -给定两位客户的空闲时间表:`slots1` 和 `slots2`,再给定会议的预计持续时间 `duration`。 +**描述**:给定两位客户的空闲时间表:$slots1$ 和 $slots2$,再给定会议的预计持续时间 $duration$。 -其中 `slots1[i] = [start_i, end_i]` 表示空闲时间第从 `start_i` 开始,到 `end_i` 结束。 `slots2` 也是如此。 +其中 $slots1[i] = [start_i, end_i]$ 表示空闲时间第从 $start_i$ 开始,到 $end_i$ 结束。$slots2$ 也是如此。 -要求:为他们安排合适的会议时间,如果有合适的会议时间,则返回该时间的起止时刻。如果没有满足要求的会议时间,就请返回一个 空数组。 +**要求**:为他们安排合适的会议时间,如果有合适的会议时间,则返回该时间的起止时刻。如果没有满足要求的会议时间,就请返回一个 空数组。 -- 会议时间:两位客户都有空参加,并且持续时间能够满足预计时间 `duration` 的最早的时间间隔。 +**说明**: -注意: 题目保证数据有效。同一个人的空闲时间不会出现交叠的情况,也就是说,对于同一个人的两个空闲时间 `[start1, end1]` 和 `[start2, end2]`,要么 `start1 > end2`,要么 `start2 > end1`。 +- **会议时间**:两位客户都有空参加,并且持续时间能够满足预计时间 $duration$ 的最早的时间间隔。 +- 题目保证数据有效。同一个人的空闲时间不会出现交叠的情况,也就是说,对于同一个人的两个空闲时间 $[start1, end1]$ 和 $[start2, end2]$,要么 $start1 > end2$,要么 $start2 > end1$。 +- $1 \le slots1.length, slots2.length \le 10^4$。 +- $slots1[i].length, slots2[i].length == 2$。 +- $slots1[i][0] < slots1[i][1]$。 +- $slots2[i][0] < slots2[i][1]$。 +- $0 \le slots1[i][j], slots2[i][j] \le 10^9$。 +- $1 \le duration \le 10^6$。 + +**示例**: + +- 示例 1: + +```python +输入:slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 8 +输出:[60,68] +``` + +- 示例 2: + +```python +输入:slots1 = [[10,50],[60,120],[140,210]], slots2 = [[0,15],[60,70]], duration = 12 +输出:[] +``` ## 解题思路 -题目保证了同一个人的空闲时间不会出现交叠。那么可以先直接对两个客户的空间时间表按照开始时间从小到大排序。然后使用分离双指针来遍历两个数组,求出重合部分,并判断重合区间是否大于等于 `duration`。具体做法如下: +### 思路 1:分离双指针 -- 先对两个数组排序。使用两个指针 `left_1`、`left_2`。`left_1` 指向第一个数组开始位置,`left_2` 指向第二个数组开始位置。 -- 遍历两个数组。计算当前两个空闲时间区间的重叠范围。 - - 如果重叠范围大于等于 `duration`,直接返回当前重叠范围开始时间和会议结束时间,即 `[start, start + duration]`,`start` 为重叠范围开始时间。 - - 如果第一个客户的空闲结束时间小于第二个客户的空闲结束时间,则令 `left_1` 右移,即 `left_1 += 1`,继续比较重叠范围。 - - 如果第一个客户的空闲结束时间大于等于第二个客户的空闲结束时间,则令 `left_2` 右移,即 `left_2 += 1`,继续比较重叠范围。 -- 直到 `left_1 == len(slots1)` 或者 `left_2 == len(slots2)` 时跳出循环,返回空数组 `[]`。 +题目保证了同一个人的空闲时间不会出现交叠。那么可以先直接对两个客户的空间时间表按照开始时间从小到大排序。然后使用分离双指针来遍历两个数组,求出重合部分,并判断重合区间是否大于等于 $duration$。具体做法如下: -## 代码 +1. 先对两个数组排序。 +2. 然后使用两个指针 $left\underline{}1$、$left\underline{}2$。$left\underline{}1$ 指向第一个数组开始位置,$left\underline{}2$ 指向第二个数组开始位置。 +3. 遍历两个数组。计算当前两个空闲时间区间的重叠范围。 + 1. 如果重叠范围大于等于 $duration$,直接返回当前重叠范围开始时间和会议结束时间,即 $[start, start + duration]$,$start$ 为重叠范围开始时间。 + 2. 如果第一个客户的空闲结束时间小于第二个客户的空闲结束时间,则令 $left\underline{}1$ 右移,即 `left_1 += 1`,继续比较重叠范围。 + 3. 如果第一个客户的空闲结束时间大于等于第二个客户的空闲结束时间,则令 $left\underline{}2$ 右移,即 `left_2 += 1`,继续比较重叠范围。 +4. 直到 $left\underline{}1 == len(slots1)$ 或者 $left\underline{}2 == len(slots2)$ 时跳出循环,返回空数组 $[]$。 + +### 思路 1:代码 ```python class Solution: @@ -54,3 +80,8 @@ class Solution: return [] ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n \times \log n + m \times \log m)$,其中 $n$、$m$ 分别为数组 $slots1$、$slots2$ 中的元素个数。 +- **空间复杂度**:$O(\log n + \log m)$。 + diff --git "a/Solutions/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260.md" "b/Solutions/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260.md" index 451152d9..84c14cdd 100644 --- "a/Solutions/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260.md" +++ "b/Solutions/1423. \345\217\257\350\216\267\345\276\227\347\232\204\346\234\200\345\244\247\347\202\271\346\225\260.md" @@ -9,31 +9,57 @@ ## 题目大意 -将卡牌排成一行,给定每张卡片的点数数组 `cardPoints`,其中 `cardPoints[i]` 表示第 `i` 张卡牌对应点数。 +**描述**:将卡牌排成一行,给定每张卡片的点数数组 $cardPoints$,其中 $cardPoints[i]$ 表示第 $i$ 张卡牌对应点数。 -每次行动,可以从行的开头或者末尾拿一张卡牌,最终保证正好拿到了 `k` 张卡牌。所得点数就是你拿到手中的所有卡牌的点数之和。 +每次行动,可以从行的开头或者末尾拿一张卡牌,最终保证正好拿到了 $k$ 张卡牌。所得点数就是你拿到手中的所有卡牌的点数之和。 -现在给定一个整数数组 `cardPoints` 和整数 `k`。 +现在给定一个整数数组 $cardPoints$ 和整数 $k$。 -要求:返回可以获得的最大点数。 +**要求**:返回可以获得的最大点数。 + +**说明**: + +- $1 \le cardPoints.length \le 10^5$。 +- $1 \le cardPoints[i] \le 10^4$ +- $1 \le k \le cardPoints.length$。 + +**示例**: + +- 示例 1: + +```python +输入:cardPoints = [1,2,3,4,5,6,1], k = 3 +输出:12 +解释:第一次行动,不管拿哪张牌,你的点数总是 1 。但是,先拿最右边的卡牌将会最大化你的可获得点数。最优策略是拿右边的三张牌,最终点数为 1 + 6 + 5 = 12。 +``` + +- 示例 2: + +```python +输入:cardPoints = [2,2,2], k = 2 +输出:4 +解释:无论你拿起哪两张卡牌,可获得的点数总是 4。 +``` ## 解题思路 +### 思路 1:滑动窗口 + 可以用固定长度的滑动窗口来做。 -由于只能从开头或末尾位置拿 `k` 张牌,则最后剩下的肯定是连续的 `len(cardPoints) - k` 张牌。要求求出 `k` 张牌可以获得的最大收益,我们可以反向先求出连续 `len(cardPoints) - k` 张牌的最小点数。则答案为 `sum(cardPoints) - min_sum`。维护一个固定长度为 `len(cardPoints) - k` 的滑动窗口,求最小和。具体做法如下: +由于只能从开头或末尾位置拿 $k$ 张牌,则最后剩下的肯定是连续的 $len(cardPoints) - k$ 张牌。要求求出 $k$ 张牌可以获得的最大收益,我们可以反向先求出连续 $len(cardPoints) - k$ 张牌的最小点数。则答案为 $sum(cardPoints) - min\underline{}sum$。维护一个固定长度为 $len(cardPoints) - k$ 的滑动窗口,求最小和。具体做法如下: -1. `window_sum` 用来维护窗口内的元素和,初始值为 `0`。`min_sum` 用来维护滑动窗口元素的最小和。初始值为 `sum(cardPoints)`。滑动窗口的长度为 `window_size`,值为 `len(cardPoints) - k`。 -2. 使用双指针 `left`、`right`。`left` 、`right` 都指向序列的第一个元素,即:`left = 0`,`right = 0`。 -3. 向右移动 `right`,先将 `window_size` 个元素填入窗口中。 -4. 当窗口元素个数为 `window_size` 时,即:`right - left + 1 >= window_size` 时,计算窗口内的元素和,并维护子数组最小和 `min_sum`。 -5. 然后向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 `k`。 -6. 重复 4 ~ 5 步,直到 `right` 到达数组末尾。 -6. 最后输出 `sum(cardPoints) - min_sum` 即为答案。 +1. $window\underline{}sum$ 用来维护窗口内的元素和,初始值为 $0$。$min\underline{}sum$ 用来维护滑动窗口元素的最小和。初始值为 $sum(cardPoints)$。滑动窗口的长度为 $window\underline{}size$,值为 $len(cardPoints) - k$。 +2. 使用双指针 $left$、$right$。$left$ 、$right$ 都指向序列的第一个元素,即:`left = 0`,`right = 0`。 +3. 向右移动 $right$,先将 $window\underline{}size$ 个元素填入窗口中。 +4. 当窗口元素个数为 $window\underline{}size$ 时,即:$right - left + 1 \ge window\underline{}size$ 时,计算窗口内的元素和,并维护子数组最小和 $min\underline{}sum$。 +5. 然后向右移动 $left$,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 $k$。 +6. 重复 4 ~ 5 步,直到 $right$ 到达数组末尾。 +7. 最后输出 $sum(cardPoints) - min\underline{}sum$ 即为答案。 -注意:如果 `window_size` 为 `0` 时需要特殊判断,此时答案为数组和 `sum(cardPoints)`。 +注意:如果 $window\underline{}size$ 为 $0$ 时需要特殊判断,此时答案为数组和 $sum(cardPoints)$。 -## 代码 +### 思路 1:代码 ```python class Solution: @@ -60,3 +86,8 @@ class Solution: return cards_sum - min_sum ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$,其中 $n$ 为数组 $cardPoints$ 中的元素数量。 +- **空间复杂度**:$O(1)$。 + diff --git "a/Solutions/1456. \345\256\232\351\225\277\345\255\220\344\270\262\344\270\255\345\205\203\351\237\263\347\232\204\346\234\200\345\244\247\346\225\260\347\233\256.md" "b/Solutions/1456. \345\256\232\351\225\277\345\255\220\344\270\262\344\270\255\345\205\203\351\237\263\347\232\204\346\234\200\345\244\247\346\225\260\347\233\256.md" index 167fba01..ec62fbf1 100644 --- "a/Solutions/1456. \345\256\232\351\225\277\345\255\220\344\270\262\344\270\255\345\205\203\351\237\263\347\232\204\346\234\200\345\244\247\346\225\260\347\233\256.md" +++ "b/Solutions/1456. \345\256\232\351\225\277\345\255\220\344\270\262\344\270\255\345\205\203\351\237\263\347\232\204\346\234\200\345\244\247\346\225\260\347\233\256.md" @@ -9,24 +9,49 @@ ## 题目大意 -给定字符串 `s` 和整数 `k`。 +**描述**:给定字符串 $s$ 和整数 $k$。 -要求:返回字符串 `s` 中长度为 `k` 的单个子字符串中可能包含的最大元音字母数。 +**要求**:返回字符串 $s$ 中长度为 $k$ 的单个子字符串中可能包含的最大元音字母数。 -注意:英文中的元音字母为(`a`, `e`, `i`, `o`, `u`)。 +**说明**: + +- 英文中的元音字母为($a$, $e$, $i$, $o$, $u$)。 +- $1 <= s.length <= 10^5$。 +- $s$ 由小写英文字母组成。 +- $1 <= k <= s.length$。 + +**示例**: + +- 示例 1: + +```python +输入:s = "abciiidef", k = 3 +输出:3 +解释:子字符串 "iii" 包含 3 个元音字母。 +``` + +- 示例 2: + +```python +输入:s = "aeiou", k = 2 +输出:2 +解释:任意长度为 2 的子字符串都包含 2 个元音字母。 +``` ## 解题思路 -固定长度的滑动窗口题目。维护一个长度为 `k` 的窗口,并统计滑动窗口中最大元音字母数。具体做法如下: +### 思路 1:滑动窗口 -1. `ans` 用来维护长度为 `k` 的单个字符串中最大元音字母数。`window_count` 用来维护窗口中元音字母数。集合 `vowel_set` 用来存储元音字母。 -2. `left` 、`right` 都指向字符串 `s` 的第一个元素,即:`left = 0`,`right = 0`。 -3. 判断 `s[right]` 是否在元音字母集合中,如果在则用 `window_count` 进行计数。 -4. 当窗口元素个数为 `k` 时,即:`right - left + 1 >= k` 时,更新 `ans`。然后判断 `s[left]` 是否为元音字母,如果是则 `window_count -= 1`,并向右移动 `left`,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 `k`。 -5. 重复 3 ~ 4 步,直到 `right` 到达数组末尾。 -6. 最后输出 `ans`。 +固定长度的滑动窗口题目。维护一个长度为 $k$ 的窗口,并统计滑动窗口中最大元音字母数。具体做法如下: -## 代码 +1. $ans$ 用来维护长度为 $k$ 的单个字符串中最大元音字母数。$window\underline{}count$ 用来维护窗口中元音字母数。集合 $vowel\underline{}set$ 用来存储元音字母。 +2. $left$ 、$right$ 都指向字符串 $s$ 的第一个元素,即:$left = 0$,$right = 0$。 +3. 判断 $s[right]$ 是否在元音字母集合中,如果在则用 $window\underline{}count$ 进行计数。 +4. 当窗口元素个数为 $k$ 时,即:$right - left + 1 \ge k$ 时,更新 $ans$。然后判断 $s[left]$ 是否为元音字母,如果是则 `window_count -= 1`,并向右移动 $left$,从而缩小窗口长度,即 `left += 1`,使得窗口大小始终保持为 $k$。 +5. 重复 $3 \sim 4$ 步,直到 $right$ 到达数组末尾。 +6. 最后输出 $ans$。 + +### 思路 1:代码 ```python class Solution: @@ -50,3 +75,8 @@ class Solution: return ans ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$,其中 $n$ 为字符串 $s$ 的长度。 +- **空间复杂度**:$O(1)$。 +