1775. 通过最少操作次数使数组的和相等

目录

【算法题】使两个数组的和相等的最少操作次数

题目描述

示例

解题分析

关键观察

解题方法

代码实现

复杂度分析

示例说明

总结与比较


【算法题】使两个数组的和相等的最少操作次数


题目描述

给定两个整数数组 nums1nums2,两个数组的长度可能不同。两个数组中所有值均在 1 到 6 之间(包含 1 和 6)。

每次操作中,你可以选择 任意一个数组 中的 任意一个整数,将它变成 1 到 6 之间的任意值。

请你返回使 nums1 中所有数的和与 nums2 中所有数的和相等的 最少操作次数。如果无法使两个数组的和相等,则返回 -1


示例

示例 1:

输入:nums1 = [1,2,3,4,5,6], nums2 = [1,1,2,2,2,2]
输出:3
解释:
通过3次操作可以使两数组和相等。
- 将 nums2[0] 变为 6,nums2变为[6,1,2,2,2,2]
- 将 nums1[5] 变为 1,nums1变为[1,2,3,4,5,1]
- 将 nums1[2] 变为 2,nums1变为[1,2,2,4,5,1]

示例 2:

输入:nums1 = [1,1,1,1,1,1,1], nums2 = [6]
输出:-1
解释:
无法通过任何操作使两数组和相等。

示例 3:

输入:nums1 = [6,6], nums2 = [1]
输出:3
解释:
- 将 nums1[0] 变为 2,nums1变为[2,6]
- 将 nums1[1] 变为 2,nums1变为[2,2]
- 将 nums2[0] 变为 4,nums2变为[4]

解题分析

我们需要最少的操作次数使两个数组的和相等。

核心问题:
让两个数组的和相等,等价于消除两个和的差值 diff = abs(sum(nums1) - sum(nums2))


关键观察

  • 每个数只能调整到 1 到 6 之间。
  • sum(nums1) > sum(nums2) 时:
    • 我们需要减少 nums1 的总和,或增加 nums2 的总和,或者两者兼顾,直到差值为 0。
  • 操作每次选择一个元素,将其变成新值以最大程度缩小差距。

每个数字的最大调整能力:

  • 对于 nums1 中的数,可以最多减少 num - 1(变成1时的最大减幅)。
  • 对于 nums2 中的数,可以最多增加 6 - num(变成6时的最大增幅)。

我们希望通过使用贡献最大的数字先调整,快速缩小差距。


解题方法

  1. 计算两个数组的和 sum1sum2
  2. 如果两者相等,返回0。
  3. 如果 sum1 < sum2,交换 nums1nums2,确保 sum1 >= sum2。这样目标统一为减少 sum1 和增加 sum2 来缩小差距。
  4. 计算差值 diff = sum1 - sum2
  5. 统计所有数字的最大贡献值放入列表 changes
    • nums1 中的数字,贡献为 num - 1
    • nums2 中的数字,贡献为 6 - num
  1. changes 降序排序。
  2. 从贡献最大的开始,依次用贡献值减少 diff,每用一次贡献即对应一次操作。
  3. diff <= 0,返回当前操作次数。
  4. 如果遍历完所有贡献值仍未使 diff <= 0,返回 -1。

代码实现

from typing import List

class Solution:
    def minOperations(self, nums1: List[int], nums2: List[int]) -> int:
        sum1, sum2 = sum(nums1), sum(nums2)
        if sum1 == sum2:
            return 0

        # 保证 sum1 是较大值,方便统一处理
        if sum1 < sum2:
            nums1, nums2 = nums2, nums1
            sum1, sum2 = sum2, sum1

        diff = sum1 - sum2

        changes = []
        # nums1 每个数字最多可减少的值
        for num in nums1:
            changes.append(num - 1)
        # nums2 每个数字最多可增加的值
        for num in nums2:
            changes.append(6 - num)

        changes.sort(reverse=True)

        operations = 0
        for change in changes:
            diff -= change
            operations += 1
            if diff <= 0:
                return operations

        return -1

复杂度分析

  • 时间复杂度:O(n log n),其中 n = len(nums1) + len(nums2),主要消耗在排序上。
  • 空间复杂度:O(n),用于存储所有贡献值。

示例说明

  • 以示例1为例:
    • nums1 = [1,2,3,4,5,6], sum = 21
    • nums2 = [1,1,2,2,2,2], sum = 10
    • 差值为11,nums1nums2贡献值分别为:
      • nums1减少贡献:[0,1,2,3,4,5](即 num-1
      • nums2增加贡献:[5,5,4,4,4,4](即 6-num
    • 合并贡献值并降序排序为:[5,5,5,5,4,4,4,4,3,2,1,0]
    • 依次用贡献值减少差值,3次操作即可使差值 ≤ 0。

总结与比较

  • 本题通过计算两个数组元素的最大调整贡献值,利用贪心策略选用最大贡献来减少差距,达到最少操作数。
  • 由于数字取值范围固定(1到6),贡献值计算非常简单,排序后贪心策略非常高效。
  • 相比枚举所有可能调整,贪心策略大幅优化性能。
  • 若题目限制更宽泛,需考虑其他优化或动态规划等方案。

这道题考察了贪心思想、数组操作、差值平衡等基本算法技巧,是理解如何通过局部最优实现全局最优的好例子。

如果你想,我可以帮你进一步讲解优化思路或者改写代码为更易读形式,欢迎随时告诉我!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值