云计算百科
云计算领域专业知识百科平台

2026-08-28:将 0 移到末尾的最少交换次数。用go语言,有一个整数数组,每次可以任选两个不同位置,交换这两个位置上的数字。现在想用尽量少的交换次数,让数组中所有的 0 都集中到数组末尾,非零

2026-08-28:将 0 移到末尾的最少交换次数。用go语言,有一个整数数组,每次可以任选两个不同位置,交换这两个位置上的数字。现在想用尽量少的交换次数,让数组中所有的 0 都集中到数组末尾,非零数字全部移到 0 的前面。

可以先数出一共有多少个 0,记为 c;再查看数组最后 c 个位置里有多少个非零数字,这个数量就是最少需要的交换次数。

1 <= nums.length <= 100。

0 <= nums[i] <= 100。

输入: nums = [0,1,0,3,12]。

输出: 2。

解释:

我们执行以下交换操作:

交换 nums[0] 和 nums[3] ,得到 nums = [3, 1, 0, 0, 12] 。

交换 nums[2] 和 nums[4] ,得到 nums = [3, 1, 12, 0, 0] 。

因此,答案是 2 。

题目来自力扣3936。

大体执行过程

  • 初始化阶段

    • 左指针 l 指向数组开头,即下标 0。
    • 右指针 r 指向数组末尾,即下标 len(nums)-1。
    • 交换次数 ans 初始为 0。
  • 循环扫描阶段
    只要左指针 l 仍然小于右指针 r,就反复检查当前左右指针指向的数字:

    • 情况一:左边不是 0
      如果 nums[l] != 0,说明当前左指针位置已经符合“非零数字在前”的要求。
      此时不需要交换,直接把左指针右移一位,继续看下一个位置。

    • 情况二:左边是 0,但右边也是 0
      如果 nums[l] == 0 且 nums[r] == 0,说明当前右指针位置已经符合“0 在末尾”的要求。
      此时也不需要交换,直接把右指针左移一位,继续寻找右边可能存在的非零数字。

    • 情况三:左边是 0,右边是非 0
      这是真正需要处理的错配情况。
      左边的这个 0 应该移动到后面,右边的这个非 0 应该移动到前面。
      因此需要一次交换,交换次数 ans 加一。
      交换后,这两个位置就都变得合理了,所以左指针右移一位,右指针左移一位,继续处理中间未处理的部分。

  • 结束条件
    当左指针和右指针相遇或交错时,说明整个数组已经被逻辑上划分好:

    • 左边部分都是非零数字;
    • 右边部分都是 0。
      循环结束,返回累计的交换次数 ans。
  • 为什么代码中没有真正交换数组元素也可以

    在这段代码里,虽然注释写了“交换”,但实际上并没有修改原数组,只增加了 ans。
    这是因为我们只关心最少交换次数,而不需要真正返回交换后的数组。
    每当遇到“左边 0、右边非 0”的情况,就把它记作一次有效交换,然后两个指针都向中间收缩,已经处理过的位置之后不会再访问,所以不真正写回数组也不会影响后面的计数。

    与题目描述中“数最后 c 个位置里的非零个数”的关系

    题目描述给出的方法是:
    先统计数组中一共有多少个 0,记为 c,然后看数组最后 c 个位置中有多少个非零数字,这个数量就是答案。

    双指针的做法和这个思路是等价的:

    • 数组中最终末尾的 0 的个数是固定的,记为 c。
    • 数组最后 c 个位置中如果有 k 个非零数字,那么这 k 个非零数字每一个都需要被交换到前面去。
    • 每交换一次,最多只能把一个非零数字从末尾区域移出。
    • 所以最少交换次数就是 k。

    双指针每次找到一个“左边 0、右边非 0”的组合并计数,实际上就是在逐个把这些末尾区域的非零数字与前面的 0 配对交换。因此它统计出来的次数正好等于最后 c 个位置中的非零数字个数。

    示例流程

    以 nums = [0,1,0,3,12] 为例:

    • 初始:l = 0,r = 4,ans = 0。
    • nums[0] = 0,nums[4] = 12 非 0,属于情况三。
      记录一次交换,ans = 1,l 移到 1,r 移到 3。
    • nums[1] = 1 非 0,属于情况一。
      l 右移到 2。
    • nums[2] = 0,nums[3] = 3 非 0,属于情况三。
      再记录一次交换,ans = 2,l 移到 3,r 移到 2。
    • 此时 l >= r,循环结束,返回 2。

    复杂度分析

    • 时间复杂度:
      每次循环至少会让左指针右移一位,或者右指针左移一位,最多扫描整个数组一次。
      因此总时间复杂度为 O(n),其中 n 是数组长度。

    • 额外空间复杂度:
      只使用了左指针、右指针和答案计数等有限几个变量,没有开辟与数组长度相关的额外空间。
      因此额外空间复杂度为 O(1)。

    Go完整代码如下:

    package main

    import (
    "fmt"
    )

    func minimumSwaps(nums []int) (ans int) {
    l, r := 0, len(nums)1
    for l < r {
    if nums[l] != 0 {
    l++
    } else if nums[r] == 0 {
    r
    } else {
    // 交换 nums[l] 和 nums[r]
    ans++
    l++
    r
    }
    }
    return
    }

    func main() {
    nums := []int{0, 1, 0, 3, 12}
    result := minimumSwaps(nums)
    fmt.Println(result)
    }

    在这里插入图片描述

    Python完整代码如下:

    # -*-coding:utf-8-*-

    from typing import List

    def minimumSwaps(nums: List[int]) > int:
    ans = 0
    l, r = 0, len(nums) 1
    while l < r:
    if nums[l] != 0:
    l += 1
    elif nums[r] == 0:
    r -= 1
    else:
    # nums[l] == 0 且 nums[r] != 0,需要一次交换
    ans += 1
    l += 1
    r -= 1
    return ans

    if __name__ == "__main__":
    nums = [0, 1, 0, 3, 12]
    result = minimumSwaps(nums)
    print(result)

    在这里插入图片描述

    C++完整代码如下:

    #include <iostream>
    #include <vector>
    using namespace std;

    int minimumSwaps(vector<int>& nums) {
    int ans = 0;
    int l = 0, r = (int)nums.size() 1;
    while (l < r) {
    if (nums[l] != 0) {
    l++;
    } else if (nums[r] == 0) {
    r;
    } else {
    // nums[l] == 0 且 nums[r] != 0,需要一次交换
    ans++;
    l++;
    r;
    }
    }
    return ans;
    }

    int main() {
    vector<int> nums = {0, 1, 0, 3, 12};
    int result = minimumSwaps(nums);
    cout << result << endl;
    return 0;
    }

    在这里插入图片描述

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 2026-08-28:将 0 移到末尾的最少交换次数。用go语言,有一个整数数组,每次可以任选两个不同位置,交换这两个位置上的数字。现在想用尽量少的交换次数,让数组中所有的 0 都集中到数组末尾,非零
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!