Leetcode 2499. Minimum Total Cost to Make Arrays Unequal
Woodyiiiiiii opened this issue · comments
这道题一开始我没有任何思路,觉得任何一次交换都会影响很大,也不知道如何作交换。
这时的思路是要排除干扰项,抽象成一条核心思路。
观察示例,为什么有的可以交换成功,有的不行呢,比如Example 3。
根据鸽巢定理,假如要交换4个数,使这4个数都跟原来的位置不同,如果其中有超过一半的数(比如4)完全相同,假如[2,2,2,3],则肯定不会出现最后所有位置数字跟原来不一样的结果。
如此,我们理清思路:
- 首先找到两个数组所有相同的位置,这些位置肯定要作交换的。
- 接下来判断是否能够仅仅在这些位置交换就够了呢,还是需要其他数值不同的位置参与进来。
- 然后根据鸽巢定理,需要判断是否存在超过一半相同的数目。所以在第一步要先找到出现最频繁的数字
- 如果小于一半,则在相同位置范围内交换即可,这时发现,我们只要加上所有位置index即可,这样是最小的i+j;否则,则从左到右遍历数组,找到最小的两数组不相同的数值,加入进交换
- 交换时,其实是把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;
}
}