通过最少操作次数使得数组的和相等
给你两个长度可能不等的整数数组 nums1
和 nums2
。两个数组中的所有值都在 1
到 6
之间(包含 1
和 6
)。
每次操作中,你可以选择 任意 数组中的任意一个整数,将它变成 1
到 6
之间 任意 的值(包含 1
和 6
)。
请你返回使 nums1
中所有数的和与 nums2
中所有数的和相等的最少操作次数。如果无法使两个数组的和相等,请返回 -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] 。
题目解析:
先讨论不能通过一定操作次数使得两个数组和相等的情况,这个时候也就是:其中一组小的全部元素变成6,大的一组全部变成元素1,两个数组仍然有差距,即6m < n
或者6n < m
,则直接返回-1,其中n、m分别是两个数组的元素个数。
然后分析题目,由于是要求最小的操作次数,我们显然是尽量能够操作较大的值/较小的值,使得两个数组尽快的接近。「说白了就是那个元素可以变化的大,先优先选择那个元素」。
假设nums1需要变大,nums2需要变小,我们首先计算每个元素的最大可以变化的量:
- nums1中的元素由于是要变大,因此最大变化量是6 - nums1[i];
- nums2中的元素由于是要变小,因此最大变化量是nums2[i] - 0;
因此我们创建一个长度为6的「因为所有变化量范围都是0~5」数组,记录每个最大变化量的次数。我们通过计算连哥哥数组之间的差值diff,然后不断从中优先减去较大的变化量进行操作,从而得到最优的操作次数。设操作变化量数组为cnt[]
- 如果cnt[i] * i <= diff,则直接梭哈,增加结果次数 ans += cnt[i]
- 否则,尝试梭哈 j = diff / cat[i] 个,增加结果次数 ans += (diff / cnt[i])
- 修改diff的值
func minOperations(nums1 []int, nums2 []int) int {
n,m := len(nums1),len(nums2)
if n * 6 < m || m * 6 < n{
return -1
}
cnt := make([]int,6)
ans := 0
sum1 := 0
for _,v := range nums1{
sum1 += v
}
sum2 := 0
for _,v := range nums2{
sum2 += v
}
if sum1 == sum2{
return 0
}else if sum1 > sum2{ // 我们使得nums1是需要变大的
nums1,nums2 = nums2,nums1
}
diff := abs(sum1 - sum2)
for _,v := range nums1{
cnt[6-v]++
}
for _,v := range nums2{
cnt[v-1]++
}
for i := 5;i > 0;i--{
if cnt[i] * i <= diff{
ans += cnt[i]
diff -= cnt[i] * i
}else{
t := diff / i
diff -= t * i
ans += t
}
if diff == 0{
break
}
}
if diff != 0{ // 如果diff还剩余,则操作一个变化为diff即消除差距
ans += 1
}
return ans
}
func abs(x int)int{
if x < 0{
return -x
}
return x
}