leetcode
leetcode 951 ~ 1000
最少交换次数来组合所有的 1

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

难度:

标签:

题目描述

代码结果

运行时间: 65 ms, 内存: 20.0 MB


/*
 * 思路:
 * 给定一个数组,目标是通过最少的交换次数将所有的1组合在一起。
 * 解决这个问题的关键是找到一个窗口,该窗口的大小等于数组中1的数量,
 * 并且该窗口内的0的数量最少。
 * 使用滑动窗口技术:
 * 1. 计算数组中1的总数k。
 * 2. 初始化一个大小为k的窗口,并计算该窗口内0的数量。
 * 3. 滑动窗口遍历数组,更新窗口内0的数量并记录最小值。
 * 4. 最小值即为所需的最少交换次数。
 * 通过Java Stream API实现。
 */
import java.util.Arrays;

public class MinSwapsStream {
    public int minSwaps(int[] data) {
        int totalOnes = (int) Arrays.stream(data).filter(num -> num == 1).count();
        if (totalOnes == 0) return 0;

        int[] prefixSum = new int[data.length + 1];
        for (int i = 0; i < data.length; i++) {
            prefixSum[i + 1] = prefixSum[i] + data[i];
        }

        int maxOnesInWindow = 0;
        for (int i = 0; i <= data.length - totalOnes; i++) {
            int onesInWindow = prefixSum[i + totalOnes] - prefixSum[i];
            maxOnesInWindow = Math.max(maxOnesInWindow, onesInWindow);
        }

        return totalOnes - maxOnesInWindow;
    }
}

解释

方法:

该题目要求将所有的1聚集到数组中的某个连续子区间中,并求出需要的最少交换次数。解题思路是使用滑动窗口。首先计算数组中1的总数n,然后维持一个长度为n的滑动窗口,通过遍历数组来确定在哪个位置的窗口内1的数量最多。由于窗口长度固定为n,窗口内最多的1意味着该区间内需要交换的0最少,因此总的交换次数就是n减去窗口内1的最大数量。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么选择滑动窗口方法来解决这个问题,这种方法与其他可能的方法相比有什么优势?
滑动窗口方法在解决这个问题时具有高效的时间复杂度和简洁的逻辑优势。通过固定窗口大小为1的总数n,可以直接关注于如何通过最小化交换次数将所有1聚集在此窗口内。这种方法避免了复杂的重排操作或多次遍历数组,只需单次遍历即可得出结果。相比于可能的其他方法,如直接计算每个位置到1的距离并排序这些距离进行交换,滑动窗口方法在时间和空间上都更加高效。
🦆
在滑动窗口中,如果数组长度小于1的总数n,该算法如何处理?
如果数组长度小于1的总数n,实际上这种情况在问题设定中是非法的,因为无法形成一个长度为n的窗口。在实际应用中应该首先检查这一点,如果发生这种情况,应返回错误或特定的输出,表示输入数据不合理。在编写代码时,可以增加一个条件检查来确保数组长度不小于n。
🦆
在实现中,`for a, b in zip(data, data[n:])`这行代码的作用是什么?具体如何更新窗口内1的数量?
这行代码用于在数组中移动滑动窗口,并更新窗口内1的数量。`for a, b in zip(data, data[n:])`迭代遍历从数组开始至数组长度减去n的每个元素(a),同时从数组的第n个元素开始至数组末尾的每个元素(b)。在每次迭代中,元素a从窗口移出,元素b进入窗口。窗口内1的数量更新为`cnt += b - a`,即从当前1的数量中减去移出的元素a的值,并加上新进入的元素b的值。这种方式能够高效地更新每个新窗口状态,无需每次重新计算窗口内的1的数量。
🦆
算法中如何确保窗口始终保持长度为n,尤其是在接近数组末尾时?
在这个算法实现中,通过`zip(data, data[n:])`自然地保证了窗口始终为长度n,因为它将数组的前半部与偏移n位置的后半部进行配对,确保每次迭代中的滑动窗口都恰好包含n个元素。一旦迭代完成,就意味着窗口从数组的开始滑动到了末尾,而且每次都是长度为n。这种机制简化了窗口大小管理,避免了在数组末尾时窗口缩小的情况。

相关问题