力扣热题——数组的最小相等和
目录
题目链接:2918. 数组的最小相等和 - 力扣(LeetCode)
题目描述
解法一:
解决思路
Java写法:
C++写法:
运行时间
时间复杂度和空间复杂度
总结
题目链接:2918. 数组的最小相等和 - 力扣(LeetCode)
注:下述题目描述和示例均来自力扣
题目描述
给你两个由正整数和 0
组成的数组 nums1
和 nums2
。
你必须将两个数组中的 所有 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 <= 10^5
0 <= nums1[i], nums2[i] <= 10^6
解法一:
解决思路
-
计算非零元素和零的数量
- 遍历两个数组,分别计算每个数组中非零元素的总和(
sum1
和sum2
)以及零的数量(zero1
和zero2
)。
- 遍历两个数组,分别计算每个数组中非零元素的总和(
-
处理特殊情况
- 情况1:两个数组都没有零
- 直接比较两个数组的非零总和是否相等。若相等,返回该总和;否则返回
-1
。
- 直接比较两个数组的非零总和是否相等。若相等,返回该总和;否则返回
- 情况2:其中一个数组没有零
- 例如,
nums1
无零,则nums2
的总和必须调整到与sum1
相等。此时需要满足:sum1 ≥ sum2 + zero2
(因为nums2
的最小总和为sum2 + zero2
,每个零替换为1)。
- 若满足条件,返回
sum1
;否则返回-1
。
- 例如,
- 情况1:两个数组都没有零
-
处理一般情况(两个数组都有零)
- 计算每个数组的最小可能总和:
nums1
的最小总和:sum1 + zero1
(每个零替换为1)。nums2
的最小总和:sum2 + zero2
(每个零替换为1)。
- 最终的总和必须至少是这两个值的较大者,因为较小的总和无法通过调整零的替换值来匹配较大的总和。
- 计算每个数组的最小可能总和:
Java写法:
public class Solution {public long minSum(int[] nums1, int[] nums2) {long sum1 = 0;int zero1 = 0;for (int num : nums1) {if (num == 0) {zero1++;} else {sum1 += num;}}long sum2 = 0;int zero2 = 0;for (int num : nums2) {if (num == 0) {zero2++;} else {sum2 += num;}}// 处理两个数组都没有0的情况if (zero1 == 0 && zero2 == 0) {return sum1 == sum2 ? sum1 : -1;}// 处理nums1没有0的情况if (zero1 == 0) {// sum1必须 >= sum2 + zero2,因为sum2的最小总和是sum2 + zero2if (sum1 >= sum2 + zero2) {return sum1;} else {return -1;}}// 处理nums2没有0的情况if (zero2 == 0) {if (sum2 >= sum1 + zero1) {return sum2;} else {return -1;}}// 其他情况,计算两者的最小可能总和的最大值long s1 = sum1 + zero1;long s2 = sum2 + zero2;return Math.max(s1, s2);}
}
C++写法:
#include <vector>
#include <algorithm> // 用于max函数using namespace std;class Solution {
public:long long minSum(vector<int>& nums1, vector<int>& nums2) {long long sum1 = 0, sum2 = 0;int zero1 = 0, zero2 = 0;// 计算nums1的非零总和和零的数量for (int num : nums1) {if (num == 0) zero1++;else sum1 += num;}// 计算nums2的非零总和和零的数量for (int num : nums2) {if (num == 0) zero2++;else sum2 += num;}// 情况1:两个数组都没有零if (zero1 == 0 && zero2 == 0) {return (sum1 == sum2) ? sum1 : -1;}// 情况2:nums1没有零,nums2必须调整到sum1的总和if (zero1 == 0) {if (sum1 >= sum2 + zero2) return sum1;else return -1;}// 情况3:nums2没有零,nums1必须调整到sum2的总和if (zero2 == 0) {if (sum2 >= sum1 + zero1) return sum2;else return -1;}// 情况4:两个数组都有零,取最小总和的较大者long long minSum1 = sum1 + zero1;long long minSum2 = sum2 + zero2;return max(minSum1, minSum2);}
};
运行时间
时间复杂度和空间复杂度
复杂度分析:
- 时间复杂度:
O(n + m)
,其中n
和m
是两个数组的长度。需要遍历两个数组各一次,统计非零元素的和与零的数量。 - 空间复杂度:
O(1)
,仅用常数空间存储变量(如sum1
,sum2
,zero1
,zero2
)。
解释:
算法仅需遍历数组两次(统计非零和零),后续所有操作均为常数时间比较和计算,因此时间复杂度为线性级,且无需额外空间。
总结
- 零的最小替换值为1,因此每个数组的最小总和为
非零和 + 零的数量
。 - 当两数组均有零时,最终总和由较大的最小总和决定。
- 单边无零时,必须满足对方数组的最小总和不超过无零数组的总和。