leetcode
leetcode 2151 ~ 2200
让数组不相等的最小总代价

让数组不相等的最小总代价

难度:

标签:

题目描述

You are given two 0-indexed integer arrays nums1 and nums2, of equal length n.

In one operation, you can swap the values of any two indices of nums1. The cost of this operation is the sum of the indices.

Find the minimum total cost of performing the given operation any number of times such that nums1[i] != nums2[i] for all 0 <= i <= n - 1 after performing all the operations.

Return the minimum total cost such that nums1 and nums2 satisfy the above condition. In case it is not possible, return -1.

 

Example 1:

Input: nums1 = [1,2,3,4,5], nums2 = [1,2,3,4,5]
Output: 10
Explanation: 
One of the ways we can perform the operations is:
- Swap values at indices 0 and 3, incurring cost = 0 + 3 = 3. Now, nums1 = [4,2,3,1,5]
- Swap values at indices 1 and 2, incurring cost = 1 + 2 = 3. Now, nums1 = [4,3,2,1,5].
- Swap values at indices 0 and 4, incurring cost = 0 + 4 = 4. Now, nums1 =[5,3,2,1,4].
We can see that for each index i, nums1[i] != nums2[i]. The cost required here is 10.
Note that there are other ways to swap values, but it can be proven that it is not possible to obtain a cost less than 10.

Example 2:

Input: nums1 = [2,2,2,1,3], nums2 = [1,2,2,3,3]
Output: 10
Explanation: 
One of the ways we can perform the operations is:
- Swap values at indices 2 and 3, incurring cost = 2 + 3 = 5. Now, nums1 = [2,2,1,2,3].
- Swap values at indices 1 and 4, incurring cost = 1 + 4 = 5. Now, nums1 = [2,3,1,2,2].
The total cost needed here is 10, which is the minimum possible.

Example 3:

Input: nums1 = [1,2,2], nums2 = [1,2,2]
Output: -1
Explanation: 
It can be shown that it is not possible to satisfy the given conditions irrespective of the number of operations we perform.
Hence, we return -1.

 

Constraints:

  • n == nums1.length == nums2.length
  • 1 <= n <= 105
  • 1 <= nums1[i], nums2[i] <= n

代码结果

运行时间: 100 ms, 内存: 27.7 MB


/*
 * 思路:
 * 1. 首先检查 nums1 和 nums2 是否已经满足 nums1[i] != nums2[i] 对于所有的 i。
 * 2. 如果满足,总代价为 0。
 * 3. 否则,遍历 nums1 和 nums2,记录所有 nums1[i] == nums2[i] 的位置。
 * 4. 为了使 nums1 满足条件,交换 nums1 中这些相同元素的位置,
 *    尽量选择代价较小的交换方式。
 * 5. 如果无法通过交换满足条件,返回 -1。
 */

import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class MinimumCostToSatisfyConditionStream {
    public int minCost(int[] nums1, int[] nums2) {
        int n = nums1.length;
        List<Integer> samePositions = IntStream.range(0, n)
                .filter(i -> nums1[i] == nums2[i])
                .boxed()
                .collect(Collectors.toList());

        if (samePositions.isEmpty()) {
            return 0;
        }

        samePositions.sort(Comparator.comparingInt(i -> nums1[i]));

        int totalCost = 0;
        Set<Integer> used = new HashSet<>();
        for (int pos : samePositions) {
            for (int i = 0; i < n; i++) {
                if (nums1[i] != nums2[i] && !used.contains(i)) {
                    totalCost += pos + i;
                    used.add(pos);
                    used.add(i);
                    int temp = nums1[pos];
                    nums1[pos] = nums1[i];
                    nums1[i] = temp;
                    break;
                }
            }
        }

        boolean valid = IntStream.range(0, n).allMatch(i -> nums1[i] != nums2[i]);

        return valid ? totalCost : -1;
    }

    public static void main(String[] args) {
        MinimumCostToSatisfyConditionStream solution = new MinimumCostToSatisfyConditionStream();
        int[] nums1 = {1, 2, 3, 4, 5};
        int[] nums2 = {1, 2, 3, 4, 5};
        System.out.println(solution.minCost(nums1, nums2)); // Output: 10
    }
}

解释

方法:

此题解尝试通过统计在nums1和nums2中相同位置上的相同元素数量,来确定最少的交换次数。首先,初始化若干变量用于记录总的交换代价、需要交换的次数、最频繁元素的数量及其值。接着,遍历数组,对于每一对相同的元素,在nums1中统计其出现的次数,并更新如果这个元素出现的次数最多,则记录它作为mode。如果最终mode的两倍小于等于需要的交换次数,说明可以通过足够的交换避免所有冲突,返回计算的总代价;否则,如果mode元素太多,导致无法通过交换避免所有冲突,返回-1。

时间复杂度:

O(n)

空间复杂度:

O(n)

代码细节讲解

🦆
在题解中,如何确定哪些元素需要被交换以确保nums1和nums2在相同位置上的元素不同?
题解通过首先遍历数组,记录下所有在相同位置上相等的元素对(x = y),并计算这些元素对的出现次数。这些元素对在后续的处理中需要被优先考虑交换,因为它们直接导致了数组元素的冲突。为了确保最小总代价,算法尝试通过找出出现次数最多的元素(即mode元素)并优先处理与这个元素相关的冲突,因为这样可以更有效地减少需要的交换次数。如果mode元素的出现次数超过一半的交换次数,则不可能通过交换解决所有冲突,这时会返回-1。
🦆
题解中提到的`mode`元素是如何影响是否能够达到最小总代价的?能否详细解释`mode`元素的角色和重要性?
在题解中,`mode`元素指的是在需要交换的元素对中出现次数最多的元素。这个元素的重要性在于它代表了最大的冲突点。如果能够优先解决这个元素的冲突,将显著减少需要进一步交换的次数。如果`mode`元素的出现次数乘以2小于等于总的交换次数(`swap_cnt`),则通过足够的交换可以解决所有冲突,否则,如果`mode`的数量太多,即使进行所有可能的交换也无法解决所有冲突,这时算法应返回-1表示无解。
🦆
为什么在第二次遍历中仅当`mode_cnt * 2 <= swap_cnt`时提前结束循环?这种条件判断的逻辑依据是什么?
这种条件判断的逻辑基于能够通过足够的交换解决所有冲突的可能性。当`mode_cnt * 2 <= swap_cnt`时,意味着即使考虑到冲突最频繁的元素(mode元素),通过足够的交换,仍有可能解决所有元素的冲突。如果这个条件成立,算法可保证有足够的交换次数来调整数组使其符合要求。如果该条件不成立,则表示即使进行所有可能的交换也无法解决所有的冲突,因此可以提前结束处理,返回无法通过交换达到要求的结果。
🦆
在题解的代码中,`cnt`数组的大小为`len(nums1) + 1`,这是否意味着nums1中的元素值不会超过数组长度?如果超过,该怎么处理?
是的,`cnt`数组的大小设置为`len(nums1) + 1`暗示了一个假设,即nums1中的元素值不超过数组的长度。这是一个常见的限制条件,使得可以直接使用元素值作为数组索引,从而简化问题的处理。如果实际情况中,nums1的元素值可能超过数组长度,这种方法就不再适用。在这种情况下,可以考虑使用哈希表(如Python中的字典)来记录每个元素的出现次数,虽然这可能会增加空间复杂度,但可以处理任意大小的元素值。

相关问题