一、问题描述
给定两个大小相等的数组 nums1 和 nums2,nums1 相对于 nums2 的优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描述。
返回 nums1 的任意排列,使其相对于 nums2 的优势最大化。
示例1:
输入:nums1 = [2,7,11,15], nums2 = [1,10,4,11]
输出:[2,11,7,15]
示例2
输入:nums1 = [12,24,8,32], nums2 = [13,25,32,11]
输出:[24,32,8,12]
提示:
- 1 <= nums1.length <= 10^5
- nums2.length == nums1.length
- 0 <= nums1[i], nums2[i] <= 10^9
二、解题方法
2.1 田忌赛马
拿到题目的第一想法:emmm,这不纯纯田忌赛马的代码版吗?先给马儿分个等级,然后挨个pk,打的过就打,打不过的就去打别人最好的马。按照这个思路有以下几个步骤:
- 给数组nums1和nums2进行升序排序
- 使用排序后的数组进行两两比较,当数组nums1中的第一个元素可以大于nums2中第一个元素时,优势加一,两数组第一项都排除(也就是不再进行比较);
- 若是nums1第一个元素<=nums2第一个元素,则需要将nums1的第一个元素与nums2的最后一个元素进行比较(nums1最小的元素(劣等马)PK nums2最大的元素(上等马)),再移除nums1第一个元素和nums2第一个元素;
- 在实际的代码编写中,我们无需真正地「移除」元素。对于 nums1,我们使用一个循环依次遍历其中的每个元素;对于 nums2,我们可以使用双指针 left和 right。如果 nums1的首个元素可以增加「优势」,就配对 left对应的元素并向右移动一个位置;如果无法配对,就配对 right 对应的元素并向左移动一个位置。
代码如下:
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var advantageCount = function(nums1, nums2) {
const n=nums1.length;
//idx记住两个数组的下标索引值
const idx1=new Array(n).fill(0);
const idx2=new Array(n).fill(0);
for(let i=0;i<n;++i){
idx1[i]=i;
idx2[i]=i;
}
//根据原数组的大小,重新排列idx中的下标索引,这样在之后根据idx值在数组中取数时,
//是按照升序顺序取数的,相当于对原数组做了一个排序
//sort中比较函数是>0就交换前后位置,这里需要注意一下
// eg:nums1[i]-nums1[j]>0,则交换数组idx1中的i、j
idx1.sort((i,j)=>nums1[i]-nums1[j]);
idx2.sort((i,j)=>nums2[i]-nums2[j]);
const ans=new Array(n).fill(0);
//left记录nums2中的位置,要是nums1中首位可以增加优势,则配对left指向的元素并人left右移一位
//要是不能增加优势,则配对right指向的元素并让right左移一位
let left=0,right=n-1;
for(let i=0;i<n;++i){
if(nums1[idx1[i]]>nums2[idx2[left]]){
ans[idx2[left]]=nums1[idx1[i]];
++left;
}else{
ans[idx2[right]]=nums1[idx1[i]];
--right;
}
}
return ans;
};