数组的最小相等和

标签: 贪心 数组

难度: Medium

给你两个由正整数和 0 组成的数组 nums1nums2

你必须将两个数组中的 所有 0 替换为 严格 正整数,并且满足两个数组中所有元素的和 相等

返回 最小 相等和 ,如果无法使两数组相等,则返回 -1

示例 1:

输入:nums1 = [3,2,0,1,0], nums2 = [6,5,0]
输出:12
解释:可以按下述方式替换数组中的 0 :
- 用 2 和 4 替换 nums1 中的两个 0 。得到 nums1 = [3,2,2,1,4] 。
- 用 1 替换 nums2 中的一个 0 。得到 nums2 = [6,5,1] 。
两个数组的元素和相等,都等于 12 。可以证明这是可以获得的最小相等和。

示例 2:

输入:nums1 = [2,0,2,0], nums2 = [1,4]
输出:-1
解释:无法使两个数组的和相等。

提示:

  • 1 <= nums1.length, nums2.length <= 105
  • 0 <= nums1[i], nums2[i] <= 106

Submission

运行时间: 55 ms

内存: 32.0 MB

class Solution:
    def minSum(self, nums1: List[int], nums2: List[int]) -> int:
        a = sum(nums1) + nums1.count(0)
        b = sum(nums2) + nums2.count(0)

        if (a < b and 0 not in nums1) or (b < a and 0 not in nums2):
            return -1

        return max(a, b)

Explain

这个题解的核心思路是首先计算每个数组中除零外所有元素的和,并加上零的个数,因为零至少需要被替换成1来使得和有效。这样,对于每个数组,计算的结果是如果所有的零被替换成1后数组的最小可能和。然后检查两个计算结果a和b。如果其中一个数组的和(假设为a)小于另一个数组的和(假设为b),同时第一个数组中不包含0(即无法通过增加零的值来调整总和),则返回-1,表示无法通过任何正整数替换0使两数组和相等。如果不是这种情况,返回a和b中的较大值,因为这就是将所有零替换为1后,能使得两数组和相等的最小值。

时间复杂度: O(n + m)

空间复杂度: O(1)

class Solution:
    def minSum(self, nums1: List[int], nums2: List[int]) -> int:
        # 计算nums1的所有非零元素之和加上零的个数(每个零至少贡献1)
        a = sum(nums1) + nums1.count(0)
        # 计算nums2的所有非零元素之和加上零的个数(每个零至少贡献1)
        b = sum(nums2) + nums2.count(0)

        # 如果一个数组的最小和小于另一个数组,并且该数组中没有零可以替换以增加总和,则返回-1
        if (a < b and 0 not in nums1) or (b < a and 0 not in nums2):
            return -1

        # 返回两个数组达到相等和的最小值
        return max(a, b)

Explore

题解中将0替换为1是为了计算两个数组在所有零至少被替换后的最小可能和。理论上,替换值可以是任意正整数,但是如果替换为1以外的其他值,虽然可以增加总和,使得两数组和更接近或相等,但这并不会影响最小可能和的初步计算结果。题解的目的是找到一个基线(即所有零至少替换为1的情况),确保两数组可以达到的最小和相等。选择1是因为它是最小的正整数,确保计算得到的和是最小可能的。

如果两个数组的和之间存在差异,并且和较小的数组中不包含0,则即使将和较大的数组中的所有0替换为任意正整数,也无法使两数组的和相等。例如,如果一个数组的和为5,另一个为10,并且和为5的数组中没有0,那么无论如何替换和为10的数组中的0,都无法减少其总和,因此无法使两数组和相等。

使用max(a, b)是基于假设所有的零都至少被替换成1的情况。在这种情况下,两个数组的最小相等和至少是a和b中的较大值。如果数组中的零较多,实际上可以选择更大的值来替换零,以达到两数组和相等的目的。然而,这不会影响最小可能和的计算,因为最小可能和基于所有零都至少替换成1的假设。如果两数组要实现相等和,他们的和至少需要达到a和b中的较大值,因为这是在最低替换条件下能达到的最小和。

可以通过单次遍历数组来同时计算总和和零的数量,从而提高代码效率。在遍历过程中,对于每个元素,可以将其加到总和中,并同时检查是否为零来增加零的计数。这样可以避免对数组的多次遍历,减少运算时间。例如,可以使用一个循环,对数组中的每个元素进行检查和计算,这样只需要一次遍历就可以得到总和和零的数量。