Woodyiiiiiii / LeetCode

My private record of Leetcode solution

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Leetcode 2499. Minimum Total Cost to Make Arrays Unequal

Woodyiiiiiii opened this issue · comments

这道题一开始我没有任何思路,觉得任何一次交换都会影响很大,也不知道如何作交换。

这时的思路是要排除干扰项,抽象成一条核心思路

观察示例,为什么有的可以交换成功,有的不行呢,比如Example 3。

根据鸽巢定理,假如要交换4个数,使这4个数都跟原来的位置不同,如果其中有超过一半的数(比如4)完全相同,假如[2,2,2,3],则肯定不会出现最后所有位置数字跟原来不一样的结果。

如此,我们理清思路:

  1. 首先找到两个数组所有相同的位置,这些位置肯定要作交换的。
  2. 接下来判断是否能够仅仅在这些位置交换就够了呢,还是需要其他数值不同的位置参与进来。
  3. 然后根据鸽巢定理,需要判断是否存在超过一半相同的数目。所以在第一步要先找到出现最频繁的数字
  4. 如果小于一半,则在相同位置范围内交换即可,这时发现,我们只要加上所有位置index即可,这样是最小的i+j;否则,则从左到右遍历数组,找到最小的两数组不相同的数值,加入进交换
  5. 交换时,其实是把index=0当作交换位置的位置,所以这是计算交换位置最小值直接是ans+=i的原因;此外,为什么equalCnt一开始不算0呢?因为最后的for循环从0开始了,隐晦地包括了

感谢@jyy的思路,这是统计(数学)+贪心的想法。

class Solution {
    public long minimumTotalCost(int[] nums1, int[] nums2) {
        int n = nums1.length;
        long ans = 0;
        boolean[] v = new boolean[n];
        Map<Integer, Integer> map = new HashMap<>();
        int maxCnt = 0;
        int maxVal = 0;
        int equalCnt = 0;

        for (int i = 0; i < n; ++i) {
            if (nums1[i] == nums2[i]) {
                map.put(nums1[i], map.getOrDefault(nums1[i], 0) + 1);
                if (map.get(nums1[i]) > maxCnt) {
                    maxCnt = map.get(nums1[i]);
                    maxVal = nums1[i];
                }
                ans += i;
                equalCnt++;
                v[i] = true;
            }
        }

        if (maxCnt * 2 <= equalCnt) {
            return ans;
        }

        for (int i = 0; i < n && maxCnt * 2 > equalCnt; ++i) {
            if (v[i]) {
                continue;
            }
            if (nums1[i] != maxVal && nums2[i] != maxVal) {
                ans += i;
                equalCnt++;
            }
        }

        return maxCnt * 2 > equalCnt ? -1 : ans;
    }
}