578 字
3 分钟
2134. 最少交换次数来组合所有的 1 II
2134. 最少交换次数来组合所有的 1 II
题目描述
交换 定义为选中两个互不相同的位置互换值。环形数组 指第一个元素和最后一个元素相邻。
给定一个二进制环形数组 nums,返回在任意位置将数组中的所有 1 聚集在一起所需的最少交换次数。
示例 1:
输入:nums = [0,1,0,1,1,0,0]输出:1示例 2:
输入:nums = [0,1,1,1,0,0,1,1,0]输出:2解法思路
核心观察:设数组中 1 的总数为 k,则最终聚集成的区域长度一定是 k。选定某个长度为 k 的窗口作为最终聚集区,「把窗口外的 1 换进来、把窗口内的 0 换出去」所需交换次数 = 窗口内 0 的个数 = k − 窗口内 1 的个数。
所以问题变成:在环形数组中找一个长度为 k 的窗口,使其中 1 的个数最多,答案 = k − max_ones。
由于数组是环形的,窗口要能跨越边界,可用 取模运算 模拟(等价于把数组复制一份接在后面滑动)。套用定长滑窗 入-更新-出:右端点 i 进窗,够 k 时更新 max_ones,左端点出窗。注意只滑 n+k-1 步避免重复。
逐步举例(nums=[0,1,1,1,0,0,1,1,0]):
k = sum(nums) = 5,即需要找长度为 5 的环形窗口。- 环形枚举各长度 5 窗口内的 1 个数:
| 窗口(下标) | 窗口内 1 数 |
|---|---|
| 0..4 → [0,1,1,1,0] | 3 |
| 1..5 → [1,1,1,0,0] | 3 |
| 2..6 → [1,1,0,0,1] | 3 |
| 3..7 → [1,0,0,1,1] | 3 |
| 4..8 → [0,0,1,1,0] | 2 |
| 5..(9) → [0,1,1,0,0] | 2 |
| 6..(10) → [1,1,0,0,1] | 3 |
| 7..(11) → [1,0,0,1,1] | 3 |
| 8..(12) → [0,0,1,1,0] | 2 |
- 最大
max_ones = 3,最少交换 =k − max_ones = 5 − 3 = 2,与预期一致。
复杂度分析
- 时间复杂度:O(n),一次遍历。
- 空间复杂度:O(1)。
代码实现
class Solution: def minSwaps(self, nums: list[int]) -> int: k = sum(nums) if k <= 1: return 0
n = len(nums) cur = sum(nums[:k]) max_ones = cur for i in range(k, n + k - 1): cur += nums[i % n] - nums[(i - k) % n] if cur > max_ones: max_ones = cur
return k - max_onesimport sysimport unittestfrom pathlib import Path
sys.path.insert(0, str(Path(__file__).parent))from solution import Solution
class TestMinSwaps(unittest.TestCase): def setUp(self): self.solution = Solution()
def test_example1(self): self.assertEqual(self.solution.minSwaps([0, 1, 0, 1, 1, 0, 0]), 1)
def test_example2(self): self.assertEqual(self.solution.minSwaps([0, 1, 1, 1, 0, 0, 1, 1, 0]), 2)
def test_example3(self): self.assertEqual(self.solution.minSwaps([1, 1, 0, 0, 1]), 0)
def test_all_ones(self): self.assertEqual(self.solution.minSwaps([1, 1, 1, 1]), 0)
def test_all_zeros(self): self.assertEqual(self.solution.minSwaps([0, 0, 0, 0]), 0)
def test_single_one(self): self.assertEqual(self.solution.minSwaps([1, 0, 0, 0]), 0)
def test_circular_case(self): self.assertEqual(self.solution.minSwaps([1, 0, 0, 1, 0]), 1)
if __name__ == "__main__": unittest.main() 2134. 最少交换次数来组合所有的 1 II
https://h1s97x.github.io/posts/coding/coding-2134-min-swaps/