「贪心笔记」通过最少操作次数使得数组的和相等

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

给你两个长度可能不等的整数数组 nums1nums2 。两个数组中的所有值都在 16 之间(包含 16)。

每次操作中,你可以选择 任意 数组中的任意一个整数,将它变成 16 之间 任意 的值(包含 16)。

请你返回使 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
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值