LeetCode 题解工作台

得到连续 K 个 1 的最少相邻交换次数

给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1 。每一次移动,你可以选择 相邻 两个数字并将它们交换。 请你返回使 nums 中包含 k 个 连续 1 的 最少 交换次数。 示例 1: 输入: nums = [1,0,0,1,0,1], k = 2 输出: 1 解释: …

category

4

题型

code_blocks

4

代码语言

hub

3

相关题

当前训练重点

困难 · 滑动窗口(状态滚动更新)

bolt

答案摘要

我们可以将数组 中的 的下标存入数组 中。接下来,我们预处理数组 的前缀和数组 ,其中 表示数组 中前 个元素的和。 对于长度为 的子数组,左侧(包含中位数)的元素个数 ,右侧的元素个数为 。

Interview AiBox logo

Interview AiBox 实时 AI 助手,陪你讲清 滑动窗口(状态滚动更新) 题型思路

试试 AiBox 面试助手arrow_forward
description

题目描述

给你一个整数数组 nums 和一个整数 k 。 nums 仅包含 0 和 1 。每一次移动,你可以选择 相邻 两个数字并将它们交换。

请你返回使 nums 中包含 k 个 连续 1 的 最少 交换次数。

 

示例 1:

输入:nums = [1,0,0,1,0,1], k = 2
输出:1
解释:在第一次操作时,nums 可以变成 [1,0,0,0,1,1] 得到连续两个 1 。

示例 2:

输入:nums = [1,0,0,0,0,0,1,1], k = 3
输出:5
解释:通过 5 次操作,最左边的 1 可以移到右边直到 nums 变为 [0,0,0,0,0,1,1,1] 。

示例 3:

输入:nums = [1,1,0,1], k = 2
输出:0
解释:nums 已经有连续 2 个 1 了。

 

提示:

  • 1 <= nums.length <= 105
  • nums[i] 要么是 0 ,要么是 1 。
  • 1 <= k <= sum(nums)
lightbulb

解题思路

方法一:前缀和 + 中位数枚举

我们可以将数组 numsnums 中的 11 的下标存入数组 arrarr 中。接下来,我们预处理数组 arrarr 的前缀和数组 ss,其中 s[i]s[i] 表示数组 arrarr 中前 ii 个元素的和。

对于长度为 kk 的子数组,左侧(包含中位数)的元素个数 x=k+12x=\frac{k+1}{2},右侧的元素个数为 y=kxy=k-x

我们枚举中位数的下标 ii,其中 x1ilen(arr)yx-1\leq i\leq len(arr)-y,那么左侧数组的前缀和 ls=s[i+1]s[i+1x]ls=s[i+1]-s[i+1-x],右侧数组的前缀和 rs=s[i+1+y]s[i+1]rs=s[i+1+y]-s[i+1]。当前中位数在 numsnums 中的下标为 j=arr[i]j=arr[i],将左侧 xx 个元素移动到 [jx+1,..j][j-x+1,..j] 所需要的操作次数为 a=(j+jx+1)×x2lsa=(j+j-x+1)\times\frac{x}{2}-ls,将右侧 yy 个元素移动到 [j+1,..j+y][j+1,..j+y] 所需要的操作次数为 b=rs(j+1+j+y)×y2b=rs-(j+1+j+y)\times\frac{y}{2},那么总的操作次数为 a+ba+b,我们取所有总的操作次数的最小值即可。

时间复杂度 O(n)O(n),空间复杂度 O(m)O(m)。其中 nnmm 分别为数组 numsnums 的长度以及数组 numsnums11 的个数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Solution:
    def minMoves(self, nums: List[int], k: int) -> int:
        arr = [i for i, x in enumerate(nums) if x]
        s = list(accumulate(arr, initial=0))
        ans = inf
        x = (k + 1) // 2
        y = k - x
        for i in range(x - 1, len(arr) - y):
            j = arr[i]
            ls = s[i + 1] - s[i + 1 - x]
            rs = s[i + 1 + y] - s[i + 1]
            a = (j + j - x + 1) * x // 2 - ls
            b = rs - (j + 1 + j + y) * y // 2
            ans = min(ans, a + b)
        return ans
speed

复杂度分析

指标
时间complexity is O(n) to gather positions plus O(number_of_ones) to slide the window and compute minimal swaps with prefix sums. Space complexity is O(number_of_ones) for storing positions and prefix sums, which is efficient given constraints.
空间Depends on the final approach
psychology

面试官常问的追问

外企场景
  • question_mark

    Look for recognition that moving adjacent ones translates into distance sums from a median index.

  • question_mark

    Expect candidates to propose sliding window over ones rather than over the entire array.

  • question_mark

    Check if prefix sums are used to prevent recomputing costs repeatedly for overlapping windows.

warning

常见陷阱

外企场景
  • error

    Attempting to slide the window over the full array of zeros and ones instead of only ones.

  • error

    Not adjusting distances relative to the median, leading to overcounting swaps.

  • error

    Neglecting edge cases where k consecutive ones already exist, resulting in unnecessary moves.

swap_horiz

进阶变体

外企场景
  • arrow_right_alt

    Compute minimum adjacent swaps for k consecutive zeros instead of ones, adapting the positions array.

  • arrow_right_alt

    Find maximum consecutive ones after at most m adjacent swaps, introducing an extra limit parameter.

  • arrow_right_alt

    Allow swaps between non-adjacent indices with cost proportional to distance and compute minimal total cost.

help

常见问题

外企场景

得到连续 K 个 1 的最少相邻交换次数题解:滑动窗口(状态滚动更新) | LeetCode #1703 困难