diff --git "a/Solutions/0480. \346\273\221\345\212\250\347\252\227\345\217\243\344\270\255\344\275\215\346\225\260.md" "b/Solutions/0480. \346\273\221\345\212\250\347\252\227\345\217\243\344\270\255\344\275\215\346\225\260.md" index bd78e7e6..84fc869d 100644 --- "a/Solutions/0480. \346\273\221\345\212\250\347\252\227\345\217\243\344\270\255\344\275\215\346\225\260.md" +++ "b/Solutions/0480. \346\273\221\345\212\250\347\252\227\345\217\243\344\270\255\344\275\215\346\225\260.md" @@ -9,55 +9,77 @@ ## 题目大意 -给定一个数组 `nums`,有一个长度为 `k` 的窗口从最左端滑动到最右端。窗口中有 `k` 个数,每次窗口向右移动 `1` 位。 +**描述**:给定一个数组 $nums$,有一个长度为 $k$ 的窗口从最左端滑动到最右端。窗口中有 $k$ 个数,每次窗口向右移动 $1$ 位。 -要求:找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。 +**要求**:找出每次窗口移动后得到的新窗口中元素的中位数,并输出由它们组成的数组。 -- 中位数:有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。 +**说明**: -例如: +- **中位数**:有序序列最中间的那个数。如果序列的长度是偶数,则没有最中间的数;此时中位数是最中间的两个数的平均数。 +- 例如: + - $[2,3,4]$,中位数是 $3$ + - $[2,3]$,中位数是 $(2 + 3) / 2 = 2.5$。 +- 你可以假设 $k$ 始终有效,即:$k$ 始终小于等于输入的非空数组的元素个数。 +- 与真实值误差在 $10 ^ {-5}$ 以内的答案将被视作正确答案。 -- `[2, 3, 4]`,中位数是 `3`。 -- `[2, 3]`,中位数是 `(2 + 3) / 2 = 2.5`。 +**示例**: + +- 示例 1: + +```python +给出 nums = [1,3,-1,-3,5,3,6,7],以及 k = 3。 + +窗口位置 中位数 +--------------- ----- +[1 3 -1] -3 5 3 6 7 1 + 1 [3 -1 -3] 5 3 6 7 -1 + 1 3 [-1 -3 5] 3 6 7 -1 + 1 3 -1 [-3 5 3] 6 7 3 + 1 3 -1 -3 [5 3 6] 7 5 + 1 3 -1 -3 5 [3 6 7] 6 + 因此,返回该滑动窗口的中位数数组 [1,-1,-1,3,5,6]。 +``` ## 解题思路 -题目要求动态维护长度为 `k` 的窗口中元素的中位数。如果对窗口元素进行排序,时间复杂度一般是 $O(k * log_2k)$。如果对每个区间都进行排序,那时间复杂度就更大了,肯定会超时。 +### 思路 1:小顶堆 + 大顶堆 -我们需要借助一个内部有序的数据结构,来降低取窗口中位数的时间复杂度。`Python` 可以借助 `heapq` 构建大顶堆和小顶堆。通过 `k` 的奇偶性和堆顶元素来获取中位数。 +题目要求动态维护长度为 $k$ 的窗口中元素的中位数。如果对窗口元素进行排序,时间复杂度一般是 $O(k \times \log k)$。如果对每个区间都进行排序,那时间复杂度就更大了,肯定会超时。 + +我们需要借助一个内部有序的数据结构,来降低取窗口中位数的时间复杂度。Python 可以借助 `heapq` 构建大顶堆和小顶堆。通过 $k$ 的奇偶性和堆顶元素来获取中位数。 接下来还要考虑几个问题:初始化问题、取中位数问题、窗口滑动中元素的添加删除操作。接下来一一解决。 初始化问题: -我们将所有大于中位数的元素放到 `heap_max`(小顶堆)中,并且元素个数向上取整。然后再将所有小于等于中位数的元素放到 `heap_min`(大顶堆)中,并且元素个数向下取整。这样当 `k` 为奇数时,`heap_max` 比 `heap_min` 多一个元素,中位数就是 `heap_max` 堆顶元素。当 `k` 为偶数时,`heap_max` 和 `heap_min` 中的元素个数相同,中位数就是 `heap_min` 堆顶元素和 `heap_max` 堆顶元素的平均数。这个过程操作如下: +我们将所有大于中位数的元素放到 $heap\underline{}max$(小顶堆)中,并且元素个数向上取整。然后再将所有小于等于中位数的元素放到 $heap\underline{}min$(大顶堆)中,并且元素个数向下取整。这样当 $k$ 为奇数时,$heap\underline{}max$ 比 $heap\underline{}min$ 多一个元素,中位数就是 $heap\underline{}max$ 堆顶元素。当 $k$ 为偶数时,$heap\underline{}max$ 和 $heap\underline{}min$ 中的元素个数相同,中位数就是 $heap\underline{}min$ 堆顶元素和 $heap\underline{}max$ 堆顶元素的平均数。这个过程操作如下: -- 先将数组中前 `k` 个元素放到 `heap_max` 中。 -- 再从 `heap_max` 中取出 `k // 2` 个堆顶元素放到 `heap_min` 中。 +- 先将数组中前 $k$ 个元素放到 $heap\underline{}max$ 中。 +- 再从 $heap\underline{}max$ 中取出 $k // 2$ 个堆顶元素放到 $heap\underline{}min$ 中。 取中位数问题(上边提到过): -- 当 `k` 为奇数时,中位数就是 `heap_max` 堆顶元素。当 `k` 为偶数时,中位数就是 `heap_max` 堆顶元素和 `heap_min` 堆顶元素的平均数。 +- 当 $k$ 为奇数时,中位数就是 $heap\underline{}max$ 堆顶元素。当 $k$ 为偶数时,中位数就是 $heap\underline{}max$ 堆顶元素和 $heap\underline{}min$ 堆顶元素的平均数。 窗口滑动过程中元素的添加和删除问题: -- 删除:每次滑动将窗口左侧元素删除。由于 `heapq` 没有提供删除中间特定元素相对应的方法。所以我们使用「延迟删除」的方式先把待删除的元素标记上,等到待删除的元素出现在堆顶时,再将其移除。我们使用 `removes` (哈希表)来记录待删除元素个数。 +- 删除:每次滑动将窗口左侧元素删除。由于 `heapq` 没有提供删除中间特定元素相对应的方法。所以我们使用「延迟删除」的方式先把待删除的元素标记上,等到待删除的元素出现在堆顶时,再将其移除。我们使用 $removes$ (哈希表)来记录待删除元素个数。 - 将窗口左侧元素删除的操作为:`removes[nums[left]] += 1`。 -- 添加:每次滑动在窗口右侧添加元素。需要根据上一步删除的结果来判断需要添加到哪一个堆上。我们用 `banlance` 记录 `heap_max` 和 `heap_min` 元素个数的差值。 - - 如果窗口左边界 `nums[left]`小于等于 `heap_max` 堆顶元素 ,则说明上一步删除的元素在 `heap_min` 上,则让 `banlance -= 1`。 - - 如果窗口左边界 `nums[left]` 大于 `heap_max` 堆顶元素,则说明上一步删除的元素在 `heap_max` 上,则上 `banlance += 1`。 - - 如果窗口右边界 `nums[right]` 小于等于 `heap_max` 堆顶元素,则说明待添加元素需要添加到 `heap_min` 上,则让 `banlance += 1`。 - - 如果窗口右边界 `nums[right]` 大于 `heap_max` 堆顶元素,则说明待添加元素需要添加到 `heap_max` 上,则让 `banlance -= 1`。 -- 经过上述操作,`banlance` 的取值为 `0`、`-2`、`2` 中的一种。需要经过调整使得 `banlance == 0`。 - - 如果 `banlance == 0`,已经平衡,不需要再做操作。 - - 如果 `banlance == -2`,则说明 `heap_min` 比 `heap_max` 的元素多了两个。则从 `heap_min` 中取出堆顶元素添加到 `heap_max` 中。 - - 如果 `banlance == 2`,则说明 `heap_max` 比 `heap_min` 的元素多了两个。则从 `heap_max` 中取出堆顶元素添加到 `heap_min` 中。 -- 调整完之后,分别检查 `heap_max` 和 `heap_min` 的堆顶元素。 - - 如果 `heap_max` 堆顶元素恰好为待删除元素,即 `removes[-heap_max[0]] > 0`,则弹出 `heap_max` 堆顶元素。 - - 如果 `heap_min` 堆顶元素恰好为待删除元素,即 `removes[heap_min[0]] > 0`,则弹出 `heap_min` 堆顶元素。 +- 添加:每次滑动在窗口右侧添加元素。需要根据上一步删除的结果来判断需要添加到哪一个堆上。我们用 $banlance$ 记录 $heap\underline{}max$ 和 $heap\underline{}min$ 元素个数的差值。 + - 如果窗口左边界 $nums[left]$小于等于 $heap\underline{}max$ 堆顶元素 ,则说明上一步删除的元素在 $heap\underline{}min$ 上,则让 `banlance -= 1`。 + - 如果窗口左边界 $nums[left]$ 大于 $heap\underline{}max$ 堆顶元素,则说明上一步删除的元素在 $heap\underline{}max$ 上,则上 `banlance += 1`。 + - 如果窗口右边界 $nums[right]$ 小于等于 $heap\underline{}max$ 堆顶元素,则说明待添加元素需要添加到 $heap\underline{}min$ 上,则让 `banlance += 1`。 + - 如果窗口右边界 $nums[right]$ 大于 $heap\underline{}max$ 堆顶元素,则说明待添加元素需要添加到 $heap\underline{}max$ 上,则让 `banlance -= 1`。 +- 经过上述操作,$banlance$ 的取值为 $0$、$-2$、$2$ 中的一种。需要经过调整使得 $banlance == 0$。 + - 如果 $banlance == 0$,已经平衡,不需要再做操作。 + - 如果 $banlance == -2$,则说明 $heap\underline{}min$ 比 $heap\underline{}max$ 的元素多了两个。则从 $heap\underline{}min$ 中取出堆顶元素添加到 $heap\underline{}max$ 中。 + - 如果 $banlance == 2$,则说明 $heap\underline{}max$ 比 $heap\underline{}min$ 的元素多了两个。则从 $heap\underline{}max$ 中取出堆顶元素添加到 $heap\underline{}min$ 中。 +- 调整完之后,分别检查 $heap\underline{}max$ 和 $heap\underline{}min$ 的堆顶元素。 + - 如果 $heap\underline{}max$ 堆顶元素恰好为待删除元素,即 $removes[-heap\underline{}max[0]] > 0$,则弹出 $heap\underline{}max$ 堆顶元素。 + - 如果 $heap\underline{}min$ 堆顶元素恰好为待删除元素,即 $removes[heap\underline{}min[0]] > 0$,则弹出 $heap\underline{}min$ 堆顶元素。 - 最后取中位数放入答案数组中,然后继续滑动窗口。 -## 代码 +### 思路 1:代码 ```python import collections @@ -111,6 +133,11 @@ class Solution: return res ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n \times \log n)$。 +- **空间复杂度**:$O(n)$。 + ## 参考资料 - 【题解】[《风 险 对 冲》:双堆对顶,大堆小堆同时维护,44ms - 滑动窗口中位数 - 力扣](https://leetcode.cn/problems/sliding-window-median/solution/feng-xian-dui-chong-shuang-dui-dui-ding-hq1dt/) diff --git "a/Solutions/0683. K \344\270\252\345\205\263\351\227\255\347\232\204\347\201\257\346\263\241.md" "b/Solutions/0683. K \344\270\252\345\205\263\351\227\255\347\232\204\347\201\257\346\263\241.md" index ec312e84..553312ae 100644 --- "a/Solutions/0683. K \344\270\252\345\205\263\351\227\255\347\232\204\347\201\257\346\263\241.md" +++ "b/Solutions/0683. K \344\270\252\345\205\263\351\227\255\347\232\204\347\201\257\346\263\241.md" @@ -9,26 +9,58 @@ ## 题目大意 -`n` 个灯泡排成一行,编号从 `1` 到 `n`。最初,所有灯泡都关闭。每天只打开一个灯泡,直到 `n` 天后所有灯泡都打开。 +**描述**:$n$ 个灯泡排成一行,编号从 $1$ 到 $n$。最初,所有灯泡都关闭。每天只打开一个灯泡,直到 $n$ 天后所有灯泡都打开。 -给定一个长度为 `n` 的灯泡数组 `blubs`,其中 `bulls[i] = x` 意味着在第`i + 1` 天,我们会把在位置 `x` 的灯泡打开,其中 `i` 从 `0` 开始,`x` 从 `1` 开始。 +给定一个长度为 $n$ 的灯泡数组 $blubs$,其中 `bulls[i] = x` 意味着在第 $i + 1$ 天,我们会把在位置 $x$ 的灯泡打开,其中 $i$ 从 $0$ 开始,$x$ 从 $1$ 开始。 -再给定一个整数 `k`。 +再给定一个整数 $k$。 -要求:输出在第几天恰好有两个打开的灯泡,使得它们中间正好有 `k` 个灯泡且这些灯泡全部是关闭的 。如果不存在这种情况,则返回 `-1`。如果有多天都出现这种情况,请返回最小的天数 。 +**要求**:输出在第几天恰好有两个打开的灯泡,使得它们中间正好有 $k$ 个灯泡且这些灯泡全部是关闭的 。如果不存在这种情况,则返回 $-1$。如果有多天都出现这种情况,请返回最小的天数 。 + +**说明**: + +- $n == bulbs.length$。 +- $1 \le n \le 2 \times 10^4$。 +- $1 \le bulbs[i] \le n$。 +- $bulbs$ 是一个由从 $1$ 到 $n$ 的数字构成的排列。 +- $0 \le k \le 2 \times 10^4$。 + +**示例**: + +- 示例 1: + +```python +输入: +bulbs = [1,3,2],k = 1 +输出:2 +解释: +第一天 bulbs[0] = 1,打开第一个灯泡 [1,0,0] +第二天 bulbs[1] = 3,打开第三个灯泡 [1,0,1] +第三天 bulbs[2] = 2,打开第二个灯泡 [1,1,1] +返回2,因为在第二天,两个打开的灯泡之间恰好有一个关闭的灯泡。 +``` + +- 示例 2: + +```python +输入:bulbs = [1,2,3],k = 1 +输出:-1 +``` ## 解题思路 -`blubs[i]` 记录的是第 `i + 1` 天开灯的位置。我们将其转换一下,使用另一个数组 `days` 来存储每个灯泡的开灯时间,其中 `days[i]` 表示第 `i` 个位置上的灯泡的开灯时间。 +### 思路 1:滑动窗口 -- 使用 `ans` 记录最小满足条件的天数。维护一个窗口 `left`、`right`。其中 `right = left + k + 1`。使得区间 `(left, right)` 中所有灯泡(总共为 `k` 个)开灯时间都晚于 `days[left]` 和 `days[right]`。 -- 对于区间 `[left, right]`,`left < i < right`: - - 如果出现 `days[i] < days[left]` 或者 `days[i] < days[right]`,说明不符合要求。将 `left`、`right` 移动到 `[i, i + k + 1]`,继续进行判断。 - - 如果对于 `left < i < right` 中所有的 `i`,都满足 `days[i] >= days[left]` 并且 `days[i] >= days[right]`,说明此时满足要求。将当前答案与 `days[left]` 和 `days[right]` 中的较大值作比较。如果比当前答案更小,则更新答案。同时将窗口向右移动 `k `位。继续检测新的不相交间隔 `[right, right + k + 1]`。 - - 注意:之所以检测新的不相交间隔,是因为如果检测的是相交间隔,原来的 `right` 位置元素仍在区间中,肯定会出现 `days[right] < days[right_new]`,不满足要求。所以此时相交的区间可以直接跳过,直接检测不相交的间隔。 -- 直到 `right >= len(days)` 时跳出循环,判断是否有符合要求的答案,并返回答案 `ans`。 +$blubs[i]$ 记录的是第 $i + 1$ 天开灯的位置。我们将其转换一下,使用另一个数组 $days$ 来存储每个灯泡的开灯时间,其中 $days[i]$ 表示第 $i$ 个位置上的灯泡的开灯时间。 -## 代码 +- 使用 $ans$ 记录最小满足条件的天数。维护一个窗口 $left$、$right$。其中 `right = left + k + 1`。使得区间 $(left, right)$ 中所有灯泡(总共为 $k$ 个)开灯时间都晚于 $days[left]$ 和 $days[right]$。 +- 对于区间 $[left, right]$,$left < i < right$: + - 如果出现 $days[i] < days[left]$ 或者 $days[i] < days[right]$,说明不符合要求。将 $left$、$right$ 移动到 $[i, i + k + 1]$,继续进行判断。 + - 如果对于 $left < i < right$ 中所有的 $i$,都满足 $days[i] \ge days[left]$ 并且 $days[i] \ge days[right]$,说明此时满足要求。将当前答案与 $days[left]$ 和 $days[right]$ 中的较大值作比较。如果比当前答案更小,则更新答案。同时将窗口向右移动 $k $位。继续检测新的不相交间隔 $[right, right + k + 1]$。 + - 注意:之所以检测新的不相交间隔,是因为如果检测的是相交间隔,原来的 $right$ 位置元素仍在区间中,肯定会出现 $days[right] < days[right_new]$,不满足要求。所以此时相交的区间可以直接跳过,直接检测不相交的间隔。 +- 直到 $right \ge len(days)$ 时跳出循环,判断是否有符合要求的答案,并返回答案 $ans$。 + +### 思路 1:代码 ```python class Solution: @@ -57,3 +89,8 @@ class Solution: return -1 ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$,其中 $n$ 为数组 $bulbs$ 的长度。 +- **空间复杂度**:$O(n)$。 + diff --git "a/Solutions/0995. K \350\277\236\347\273\255\344\275\215\347\232\204\346\234\200\345\260\217\347\277\273\350\275\254\346\254\241\346\225\260.md" "b/Solutions/0995. K \350\277\236\347\273\255\344\275\215\347\232\204\346\234\200\345\260\217\347\277\273\350\275\254\346\254\241\346\225\260.md" index 55329d94..c28e4509 100644 --- "a/Solutions/0995. K \350\277\236\347\273\255\344\275\215\347\232\204\346\234\200\345\260\217\347\277\273\350\275\254\346\254\241\346\225\260.md" +++ "b/Solutions/0995. K \350\277\236\347\273\255\344\275\215\347\232\204\346\234\200\345\260\217\347\277\273\350\275\254\346\254\241\346\225\260.md" @@ -9,41 +9,70 @@ ## 题目大意 -给定一个仅包含 `0` 和 `1` 的数组 `nums`,再给定一个整数 `k`。进行一次 `k` 位翻转包括选择一个长度为 `k` 的(连续)子数组,同时将子数组中的每个 `0` 更改为 `1`,而每个 `1` 更改为 `0`。 +**描述**:给定一个仅包含 $0$ 和 $1$ 的数组 $nums$,再给定一个整数 $k$。进行一次 $k$ 位翻转包括选择一个长度为 $k$ 的(连续)子数组,同时将子数组中的每个 $0$ 更改为 $1$,而每个 $1$ 更改为 $0$。 -要求:返回所需的 `k` 位翻转的最小次数,以便数组没有值为 `0` 的元素。如果不可能,返回 `-1`。 +**要求**:返回所需的 $k$ 位翻转的最小次数,以便数组没有值为 $0$ 的元素。如果不可能,返回 $-1$。 + +**说明**: + +- **子数组**:数组的连续部分。 +- $1 <= nums.length <= 105$。 +- $1 <= k <= nums.length$。 + +**示例**: + +- 示例 1: + +```python +输入:nums = [0,1,0], K = 1 +输出:2 +解释:先翻转 A[0],然后翻转 A[2]。 +``` + +- 示例 2: + +```python +输入:nums = [0,0,0,1,0,1,1,0], K = 3 +输出:3 +解释: +翻转 A[0],A[1],A[2]: A变成 [1,1,1,1,0,1,1,0] +翻转 A[4],A[5],A[6]: A变成 [1,1,1,1,1,0,0,0] +翻转 A[5],A[6],A[7]: A变成 [1,1,1,1,1,1,1,1] +``` ## 解题思路 -每次需要翻转的起始位置肯定是遇到第一个元素为 `0` 的位置开始反转,如果能够使得整个数组不存在 `0`,即返回 `ans` 作为反转次数。 +### 思路 1:滑动窗口 + +每次需要翻转的起始位置肯定是遇到第一个元素为 $0$ 的位置开始反转,如果能够使得整个数组不存在 $0$,即返回 $ans$ 作为反转次数。 同时我们还可以发现: -- 如果某个元素反转次数为奇数次,元素会由 `0 -> 1`,`1 -> 0`。 +- 如果某个元素反转次数为奇数次,元素会由 $0 \rightarrow 1$,$1 \rightarrow 0$。 - 如果某个元素反转次数为偶数次,元素不会发生变化。 -每个第 `i` 位置上的元素只会被前面 `[i - k + 1, i - 1]` 的元素影响。所以我们只需要知道前面 `k - 1` 个元素翻转次数的奇偶性就可以了。 +每个第 $i$ 位置上的元素只会被前面 $[i - k + 1, i - 1]$ 的元素影响。所以我们只需要知道前面 $k - 1$ 个元素翻转次数的奇偶性就可以了。 -同时如果我们知道了前面 `k - 1` 个元素的翻转次数就可以直接修改 `nums[i]` 了。 +同时如果我们知道了前面 $k - 1$ 个元素的翻转次数就可以直接修改 $nums[i]$ 了。 -我们使用 `flip_count` 记录第 `i` 个元素之前 `k - 1` 个位置总共被反转了多少次,或者 `flip_count` 是大小为 `k - 1` 的滑动窗口。 +我们使用 $flip\underline{}count$ 记录第 $i$ 个元素之前 $k - 1$ 个位置总共被反转了多少次,或者 $flip\underline{}count$ 是大小为 $k - 1$ 的滑动窗口。 -- 如果前面第 `k - 1` 个元素翻转了奇数次,则如果 `nums[i] == 1`,则 `nums[i]` 也被翻转成了 `0`,需要再翻转 `1` 次。 -- 如果前面第 `k - 1` 个元素翻转了偶数次,则如果 `nums[i] == 0`,则 `nums[i]` 也被翻转成为了 `0`,需要再翻转 `1` 次。 +- 如果前面第 $k - 1$ 个元素翻转了奇数次,则如果 $nums[i] == 1$,则 $nums[i]$ 也被翻转成了 $0$,需要再翻转 $1$ 次。 +- 如果前面第 $k - 1$ 个元素翻转了偶数次,则如果 $nums[i] == 0$,则 $nums[i]$ 也被翻转成为了 $0$,需要再翻转 $1$ 次。 这两句写成判断语句可以写为:`if (flip_count + nums[i]) % 2 == 0:`。 -因为 `0 <= nums[i] <= 1`,所以我们可以用 `0` 和 `1` 以外的数,比如 `2` 来标记第 `i` 个元素发生了翻转,即 `nums[i] = 2`。这样在遍历到第 `i` 个元素时,如果有 `nums[i - k] == 2`,则说明 `nums[i - k]` 发生了翻转。同时根据 `flip_count` 和 `nums[i]` 来判断第 `i` 位是否需要进行翻转。 +因为 $0 <= nums[i] <= 1$,所以我们可以用 $0$ 和 $1$ 以外的数,比如 $2$ 来标记第 $i$ 个元素发生了翻转,即 `nums[i] = 2`。这样在遍历到第 $i$ 个元素时,如果有 $nums[i - k] == 2$,则说明 $nums[i - k]$ 发生了翻转。同时根据 $flip\underline{}count$ 和 $nums[i]$ 来判断第 $i$ 位是否需要进行翻转。 整个算法的具体步骤如下: -- 使用 `res` 记录最小翻转次数。使用 `flip_count` 记录窗口内前 `k - 1 ` 位元素的翻转次数。 -- 遍历数组 `nums`,对于第 `i` 位元素: - - 如果 `i - k >= 0`,并且 `nums[i - k] == 2`,需要缩小窗口,将翻转次数减一。(此时窗口范围为 `[i - k + 1, i - 1]`)。 - - 如果 `(flip_count + nums[i]) % 2 == 0`,则说明 `nums[i]` 还需要再翻转一次,将 `nums[i]` 标记为 `2`,同时更新窗口内翻转次数 `flip_count` 和答案最小翻转次数 `ans`。 -- 遍历完之后,返回 `res`。 +- 使用 $res$ 记录最小翻转次数。使用 $flip\underline{}count$ 记录窗口内前 $k - 1 $ 位元素的翻转次数。 +- 遍历数组 $nums$,对于第 $i$ 位元素: + - 如果 $i - k >= 0$,并且 $nums[i - k] == 2$,需要缩小窗口,将翻转次数减一。(此时窗口范围为 $[i - k + 1, i - 1]$)。 + - 如果 $(flip\underline{}count + nums[i]) \mod 2 == 0$,则说明 $nums[i]$ 还需要再翻转一次,将 $nums[i]$ 标记为 $2$,同时更新窗口内翻转次数 $flip\underline{}count$ 和答案最小翻转次数 $ans$。 +- 遍历完之后,返回 $res$。 -## 代码 +### 思路 1:代码 ```python class Solution: @@ -62,3 +91,8 @@ class Solution: return ans ``` +### 思路 1:复杂度分析 + +- **时间复杂度**:$O(n)$,其中 $n$ 为数组 $nums$ 的长度。 +- **空间复杂度**:$O(1)$。 +