2026-05-03:避免禁用值的最小交换次数。用go语言,给定两个长度为 n 的整数数组 nums 和 forbidden。你需要通过反复执行交换操作来调整

网易专栏6天前发布 nxnqh
11 0 0

🤖 AI总结

主题

避免禁用值的最小交换次数算法解析

摘要

本文解析力扣3785题,提供判断无解、统计冲突、计算最小交换次数的算法及Go/Python/C++代码实现。

关键信息

  • 1 给定nums和forbidden数组,通过交换使每个位置nums[i]≠forbidden[i]
  • 2 最小交换次数由冲突总数和冲突数字最大次数决定
  • 3 时间复杂度O(n),空间复杂度O(n)

2026-05-03:避免禁用值的最小交换次数。用go语言,给定两个长度为 n 的整数数组 nums 和 forbidden。你需要通过反复执行交换操作来调整 nums,使得对每个位置 i,都满足 nums[i] ≠ forbidden[i]。

交换操作的规则是:你可以任意次选择两个不同的下标 i 和 j,然后交换 nums[i] 和 nums[j] 的值。交换次数可以是零次。

目标是:在所有能满足“每个位置 i 的 nums[i 都不能等于 forbidden[i]”的调整方案中,找出所需交换次数的最小值;如果不存在任何办法能做到上述条件,则返回 -1。

1 <= n == nums.length == forbidden.length <= 100000。

1 <= nums[i], forbidden[i] <= 1000000000。

输入: nums = [1,2,3], forbidden = [3,2,1]。

输出: 1。

解释:

一种最优的交换方案:

选择 nums 中下标 i = 0 和 j = 1,交换它们,得到 nums = [2, 1, 3]。

交换完成后,对于每个下标 i,nums[i] 都不等于 forbidden[i]。

题目来自力扣3785。

解题过程+复杂度分析 一、先明确题目核心要求

1. 给定两个等长数组numsforbidden,长度为n

  • 2. 操作:任意交换 nums 中两个不同下标的元素,可以交换无数次。

  • 3. 目标:调整后每个位置 i 都满足 nums[i] ≠ forbidden[i],求最少交换次数;如果做不到,返回 -1。

  • 4. 示例:nums=[1,2,3]forbidden=[3,2,1]→ 最少交换 1 次。

    二、分步骤详细解题过程 步骤1:判断是否存在合法方案(无解判断)

    我们首先要确定:能不能通过交换让所有位置都不冲突
    判断规则:
    nums里的所有数字 +forbidden里的所有数字合并统计每个数字的总出现次数
    如果有任何一个数字的总次数 > n→ 直接返回 -1(无解)。

    原理:
    数组总长度只有 n,每个位置最终只能放一个数字。如果某个数字总数超过 n,无论怎么放,必然有至少一个位置会和 forbidden[i] 冲突,所以无解。

    步骤2:统计「天然冲突位置」数量

    遍历每一个位置i
    如果原始 nums[i] == forbidden[i]→ 这个位置是冲突位置,我们把所有这样的位置总数记为k

    示例:
    nums = [1,2,3],forbidden = [3,2,1]
    位置0:1≠3 → 不冲突
    位置1:2==2 → 冲突
    位置2:3≠1 → 不冲突
    所以冲突总数k = 1

    步骤3:统计冲突位置中「重复数字的最大出现次数」

    在所有冲突位置里,统计每个数字出现了多少次,找到出现次数最多的那个数字的次数,记为mx

    示例:
    只有位置1是冲突位置,数字是 2 → 冲突位置里数字2出现1次 →mx = 1

    原理:
    如果某个数字在冲突位置里扎堆出现,比如 5 个冲突位置全是数字3,那这些位置无法内部两两交换解决,必须用这个最大次数作为最低交换限制。

    步骤4:计算最小交换次数

    最终答案取两个值的最大值

    1.(冲突总数 k + 1) / 2:两两交换冲突位置,是最优的交换方式(一次交换解决两个冲突)。

  • 2.冲突位置里重复数字的最大次数 mx:扎堆的冲突数字必须单独处理,是硬性最低要求。

    示例计算:
    k=1 → (1+1)/2 = 1
    mx=1
    最大值 = 1 → 答案就是 1,和题目输出一致。

    三、时间复杂度分析

    整个算法只做了3次线性遍历

    1. 遍历 nums 统计数字频率 → O(n)

  • 2. 遍历 forbidden 做无解判断 + 统计冲突位置 + 统计重复数字 → O(n)

  • 3. 简单数学计算 → O(1)

    总时间复杂度:O(n)
    (n 是数组长度,满足题目 n ≤ 10⁵ 的高效运行要求)

    四、额外空间复杂度分析

    算法只使用了**哈希表(字典)**存储数字频率:

    • 哈希表最多存储2n个不同数字(nums+forbidden),但实际远小于这个值。

  • • 没有使用递归、二维数组等额外空间。

    总额外空间复杂度:O(n)

    总结

    1. 解题四步:判断无解 → 统计冲突位置 → 统计冲突数字最大值 → 计算最小交换

  • 2. 时间复杂度:O(n)(线性时间,高效处理大数据);

  • 3. 额外空间复杂度:O(n)(仅用哈希表存储频率)。

    Go完整代码如下:

    package main

    import (
    "fmt"
    )

    func minSwaps(nums, forbidden []int)int {
    n := len(nums)
    total := map[int]int{}
    for _, x := range nums {
    total[x]++
    }

    cnt := map[int]int{}
    k, mx := 0, 0
    for i, x := range forbidden {
    total[x]++
    if total[x] > n {
    return-1
    }
    if x == nums[i] {
    k++
    cnt[x]++
    mx = max(mx, cnt[x])
    }
    }

    return max((k+1)/2, mx)
    }

    func main() {
    nums := []int{1, 2, 3}
    forbidden := []int{3, 2, 1}
    result := minSwaps(nums, forbidden)
    fmt.Println(result)
    }

    2026-05-03:避免禁用值的最小交换次数。用go语言,给定两个长度为 n 的整数数组 nums 和 forbidden。你需要通过反复执行交换操作来调整

    Python完整代码如下:

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

    def minSwaps(nums, forbidden):
    n = len(nums)
    total = {}
    for x in nums:
    total[x] = total.get(x, 0) + 1

    cnt = {}
    k, mx = 0, 0
    for i, x in enumerate(forbidden):
    total[x] = total.get(x, 0) + 1
    if total[x] > n:
    return-1
    if x == nums[i]:
    k += 1
    cnt[x] = cnt.get(x, 0) + 1
    mx = max(mx, cnt[x])

    return max((k + 1) // 2, mx)

    def main():
    nums = [1, 2, 3]
    forbidden = [3, 2, 1]
    result = minSwaps(nums, forbidden)
    print(result)

    if __name__ == "__main__":
    main()

    2026-05-03:避免禁用值的最小交换次数。用go语言,给定两个长度为 n 的整数数组 nums 和 forbidden。你需要通过反复执行交换操作来调整

    C++完整代码如下:

      
    




    using namespace std;

    int minSwaps(vector& nums, vector& forbidden) {
    int n = nums.size();
    unordered_map total;
    for (int x : nums) {
    total[x]++;
    }

    unordered_map cnt;
    int k = 0, mx = 0;
    for (int i = 0; i < forbidden.size(); i++) {
    int x = forbidden[i];
    total[x]++;
    if (total[x] > n) {
    return-1;
    }
    if (x == nums[i]) {
    k++;
    cnt[x]++;
    mx = max(mx, cnt[x]);
    }
    }

    return max((k + 1) / 2, mx);
    }

    int main() {
    vector nums = {1, 2, 3};
    vector forbidden = {3, 2, 1};
    int result = minSwaps(nums, forbidden);
    cout << result << endl;
    return0;
    }

    2026-05-03:避免禁用值的最小交换次数。用go语言,给定两个长度为 n 的整数数组 nums 和 forbidden。你需要通过反复执行交换操作来调整

    我们相信人工智能为普通人提供了一种“增强工具”,并致力于分享全方位的AI知识。在这里,您可以找到最新的AI科普文章、工具评测、提升效率的秘籍以及行业洞察。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让AI助力您的未来发展。

    © 版权声明

    相关文章