列表

详情


2134. 最少交换次数来组合所有的 1 II

交换 定义为选中一个数组中的两个 互不相同 的位置并交换二者的值。

环形 数组是一个数组,可以认为 第一个 元素和 最后一个 元素 相邻

给你一个 二进制环形 数组 nums ,返回在 任意位置 将数组中的所有 1 聚集在一起需要的最少交换次数。

 

示例 1:

输入:nums = [0,1,0,1,1,0,0]
输出:1
解释:这里列出一些能够将所有 1 聚集在一起的方案:
[0,0,1,1,1,0,0] 交换 1 次。
[0,1,1,1,0,0,0] 交换 1 次。
[1,1,0,0,0,0,1] 交换 2 次(利用数组的环形特性)。
无法在交换 0 次的情况下将数组中的所有 1 聚集在一起。
因此,需要的最少交换次数为 1 。

示例 2:

输入:nums = [0,1,1,1,0,0,1,1,0]
输出:2
解释:这里列出一些能够将所有 1 聚集在一起的方案:
[1,1,1,0,0,0,0,1,1] 交换 2 次(利用数组的环形特性)。
[1,1,1,1,1,0,0,0,0] 交换 2 次。
无法在交换 0 次或 1 次的情况下将数组中的所有 1 聚集在一起。
因此,需要的最少交换次数为 2 。

示例 3:

输入:nums = [1,1,0,0,1]
输出:0
解释:得益于数组的环形特性,所有的 1 已经聚集在一起。
因此,需要的最少交换次数为 0 。

 

提示:

原站题解

去查看

上次编辑到这里,代码来自缓存 点击恢复默认模板
class Solution { public: int minSwaps(vector<int>& nums) { } };

python3 解法, 执行用时: 248 ms, 内存消耗: 19.8 MB, 提交时间: 2023-06-20 14:58:41

class Solution:
    def minSwaps(self, nums: List[int]) -> int:
        n = len(nums)
        cnt = sum(nums)
        if cnt == 0:
            return 0
        
        cur = 0
        for i in range(cnt):
            cur += (1 - nums[i])
        
        ans = cur
        for i in range(1, n):
            if nums[i - 1] == 0:
                cur -= 1
            if nums[(i + cnt - 1) % n] == 0:
                cur += 1
            ans = min(ans, cur)
        return ans

cpp 解法, 执行用时: 80 ms, 内存消耗: 78.5 MB, 提交时间: 2023-06-20 14:58:01

class Solution {
public:
    int minSwaps(vector<int>& nums) {
        int n = nums.size();
        int cnt = accumulate(nums.begin(), nums.end(), 0); // 0 的个数
        if (cnt == 0) {
            return 0;
        }
        
        int cur = 0;
        for (int i = 0; i < cnt; ++i) {
            cur += (1 - nums[i]);
        }
        int ans = cur;
        for (int i = 1; i < n; ++i) {
            if (nums[i - 1] == 0) {
                --cur;
            }
            if (nums[(i + cnt - 1) % n] == 0) {
                ++cur;
            }
            ans = min(ans, cur);
        }
        return ans;
    }
};

java 解法, 执行用时: 14 ms, 内存消耗: 54.7 MB, 提交时间: 2023-06-20 14:56:51

class Solution {
    public int minSwaps(int[] nums) {
        int n = nums.length;
        int ans = n, oneCnt = 0;

        // 统计数组中 1 的数量
        for (int num : nums) {
            if (num == 1) oneCnt++;
        }

        // 开一个宽度为 oneCnt 的窗口, 统计窗口里面 0 的数量 zeroCnt
        // 最少的 zeroCnt 即为此题答案
        for (int i = 0, zeroCnt = 0; i < 2 * n; i++) {
            if (i >= oneCnt) {
                ans = Math.min(ans, zeroCnt);

                // 右移窗口时,被移除的数字是 0 则 zeroCnt--
                if (nums[(i - oneCnt) % n] == 0) {
                    zeroCnt--;
                }
            }

            if (nums[i % n] == 0) zeroCnt++;
        }

        return ans;
    }
}

golang 解法, 执行用时: 84 ms, 内存消耗: 8.6 MB, 提交时间: 2023-06-20 14:55:29

// 断环成链 + 滑动窗口
func minSwaps(nums []int) int {
	tot1 := 0
	for _, num := range nums {
		tot1 += num
	}
	cnt1, maxCnt1 := 0, 0
	nums = append(nums, nums...) // 断环成链
	for i, num := range nums {
		cnt1 += num
		if i >= tot1 { // 滑窗
			cnt1 -= nums[i-tot1]
			if cnt1 > maxCnt1 {
				maxCnt1 = cnt1
			}
		}
	}
	return tot1 - maxCnt1
}

python3 解法, 执行用时: 160 ms, 内存消耗: 21.3 MB, 提交时间: 2023-06-20 14:54:39

# 滑动窗口
class Solution:
    def minSwaps(self, nums: List[int]) -> int:
        n, cnt, nums = len(nums), nums.count(1), nums * 2
        ans = cnt_ = sum(nums[:cnt])
        for i in range(n):
            if nums[i] != nums[i + cnt]:
                cnt_ += nums[i + cnt] - nums[i]
                ans = max(ans, cnt_)
        return cnt - ans

上一题