开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第18天,点击查看活动详情
给你两个长度可能不等的整数数组 nums1 和 nums2 。两个数组中的所有值都在 1 到 6 之间(包含 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 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums2[0] 变为 6 。 nums1 = [1,2,3,4,5,6], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[5] 变为 1 。 nums1 = [1,2,3,4,5,1], nums2 = [6,1,2,2,2,2] 。
- 将 nums1[2] 变为 2 。 nums1 = [1,2,2,4,5,1], nums2 = [6,1,2,2,2,2] 。
示例 2:
输入: nums1 = [1,1,1,1,1,1,1], nums2 = [6]
输出: -1
解释: 没有办法减少 nums1 的和或者增加 nums2 的和使二者相等。
示例 3:
输入: nums1 = [6,6], nums2 = [1]
输出: 3
解释: 你可以通过 3 次操作使 nums1 中所有数的和与 nums2 中所有数的和相等。以下数组下标都从 0 开始。
- 将 nums1[0] 变为 2 。 nums1 = [2,6], nums2 = [1] 。
- 将 nums1[1] 变为 2 。 nums1 = [2,2], nums2 = [1] 。
- 将 nums2[0] 变为 4 。 nums1 = [2,2], nums2 = [4] 。
提示:
1 <= nums1.length, nums2.length <= 10^51 <= nums1[i], nums2[i] <= 6
思路
一个长度为n的数组和最大值为6*n,最小值为n。当nums1和nums2的长度比大于6时,无法使二者相等,即较短的数组最大值小于较长数组的最小值,无论怎么操作都无法相等。
设nums1的和大于nums2的和,和之差为diff。我们需要修改nums1和nums2的值使diff等0。为了使操作步骤最少,nums1中的值应该往小修改,nums2的值应该往大修改,设每次操作后的新值和原始值的差为c,我们应该让c最大化。
首先先把nums1降序排列,nums2升序排列,遍历nums1和nums2,记当前下标分别为i和j,c1 = nums1[i] - 1, c2 = 6 - nums2[j],当c1 > c2 时,diff = diff - c1,i++,否则 diff = diff - c2, j++,当diff <= 0时跳出循环。
因为数组值范围在1到6之间,我们可以用两个数组cs1和cs2分别记录nums1和nums2中1到6每个值出现的次数,我们用i遍历1到6,
diff1 = diff - (6 - i + 1 - 1) * cs1[6 - i + 1] + (6 - i) * cs2[i] = diff - (6 - i) * (cs1[6 - i + 1] + cs2[i])
- 当
diff > 0时,操作步骤增加cs1[6 - i + 1] + cs2[i],diff = diff1 - 当
diff <= 0时,操作步骤增加Math.ceil(diff / (6 - i)),跳出循环。
解题
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number}
*/
var minOperations = function (nums1, nums2) {
let m = nums1.length;
let n = nums2.length;
if (m > n * 6 || n > m * 6) return -1;
const counter = new Array(7).fill(0);
let diff = 0;
for (let i = 0; i < m; i++) {
diff += nums1[i];
counter[nums1[i]]++;
}
for (let i = 0; i < n; i++) {
diff -= nums2[i];
counter[6 - nums2[i] + 1]++;
}
let offset = diff > 0 ? 1 : 6;
let flag = diff > 0 ? 1 : -1;
let res = 0;
diff = Math.abs(diff);
for (let i = 5; i >= 1; i--) {
const count = counter[flag * i + offset];
const num = Math.ceil(diff / i);
if (count >= num) {
res += num;
break;
} else {
res += count;
diff -= i * count;
}
}
return res;
};