leetcode
leetcode 2201 ~ 2250
使数组中所有元素相等的最小操作数 II

使数组中所有元素相等的最小操作数 II

难度:

标签:

题目描述

You are given two integer arrays nums1 and nums2 of equal length n and an integer k. You can perform the following operation on nums1:

  • Choose two indexes i and j and increment nums1[i] by k and decrement nums1[j] by k. In other words, nums1[i] = nums1[i] + k and nums1[j] = nums1[j] - k.

nums1 is said to be equal to nums2 if for all indices i such that 0 <= i < n, nums1[i] == nums2[i].

Return the minimum number of operations required to make nums1 equal to nums2. If it is impossible to make them equal, return -1.

 

Example 1:

Input: nums1 = [4,3,1,4], nums2 = [1,3,7,1], k = 3
Output: 2
Explanation: In 2 operations, we can transform nums1 to nums2.
1st operation: i = 2, j = 0. After applying the operation, nums1 = [1,3,4,4].
2nd operation: i = 2, j = 3. After applying the operation, nums1 = [1,3,7,1].
One can prove that it is impossible to make arrays equal in fewer operations.

Example 2:

Input: nums1 = [3,8,5,2], nums2 = [2,4,1,6], k = 1
Output: -1
Explanation: It can be proved that it is impossible to make the two arrays equal.

 

Constraints:

  • n == nums1.length == nums2.length
  • 2 <= n <= 105
  • 0 <= nums1[i], nums2[j] <= 109
  • 0 <= k <= 105

代码结果

运行时间: 55 ms, 内存: 29.9 MB


/*
 * 思路:
 * 使用Java Stream处理:
 * 1. 计算每个对应位置的差值。
 * 2. 分别统计增加和减少的总次数。
 * 3. 如果增加和减少的次数不等,则返回-1。
 * 4. 如果k为0,且所有差值都为0,则返回0,否则返回-1。
 * 5. 否则,返回总操作次数。总操作次数为增加或减少总次数的较大值(因为增加和减少应该相等)。
 */
import java.util.stream.IntStream;
public class Solution {
    public int minOperations(int[] nums1, int[] nums2, int k) {
        long[] counts = IntStream.range(0, nums1.length)
            .mapToLong(i -> nums1[i] - nums2[i])
            .filter(diff -> diff != 0)
            .map(diff -> diff > 0 ? diff / k : -diff / k)
            .toArray();
        long add = 0, subtract = 0;
        for (long count : counts) {
            if (count > 0) subtract += count;
            else add += -count;
        }
        return add == subtract ? (int)add : -1;
    }
}

解释

方法:

题解的核心思想是首先计算两个数组中对应位置元素的差值,并检查这些差值是否能被k整除。若不能整除,则直接返回-1,因为不能通过指定操作使两数组相等。如果能整除,则计算每个位置需要的操作次数(差值除以k的商),并累加。特别地,对于所有正差值的累加总和(即需要增加的总次数),单独计算为变量ans。若总操作次数为0,说明两数组已相等,返回ans;否则返回-1。

时间复杂度:

O(n)

空间复杂度:

O(1)

代码细节讲解

🦆
为什么在题解中,当差值不是k的倍数时直接返回-1而不考虑其他可能的操作组合来调整差值?
在题解中,如果差值不是k的倍数,则无法通过添加或减少k的倍数的方式使两个元素相等。这是因为每次操作只能增加或减少k,因此任何不是k的倍数的差值都无法恰好通过这种操作方式调整为0。因此,如果存在任何一个差值不是k的倍数,整个数组调整任务就不可能完成,所以直接返回-1是正确的处理方式。
🦆
题解中提到`如果x > 0: ans += x // k`,这里为什么只对正差值累加操作次数,负差值的处理逻辑是什么?
在题解中,如果差值x为正,表示需要增加元素的值来匹配另一数组中的对应元素。故累加正差值的操作次数到变量ans。对于负差值(即x < 0),这表示需要减少元素的值,此时x // k将自动得到一个负数,这种操作会在变量sum中被累加,但不直接影响ans,因为ans只计算增加操作的次数。
🦆
题解的算法在处理`sum += x // k`时,是否考虑了累加的正负号对最终结果的影响?
是的,算法中的`sum += x // k`确实考虑了累加的正负号。这里的sum变量累加了所有差值除以k的商,包括正数和负数。最终,算法检查sum是否为0来确定是否所有的操作(增加与减少)彼此抵消,仅在sum为0(即所有操作相互抵消,数组已经平衡)时返回ans,否则返回-1。
🦆
在题解的代码中,`elif x: return -1`这个条件是在检查什么情况?如果k为0,为什么不能有任何非零差值?
这个条件检查的是k为0的情况下,是否存在非零差值。如果k为0,表明不能通过增加或减少任何值(因为0乘以任何数都是0)来调整数组元素的值。因此,如果存在任何非零差值,这意味着两个元素无法通过任何操作变得相等,因此返回-1。这是因为在没有有效操作(操作数k为0)的条件下,任何非零差值都说明数组无法调整为全等。

相关问题