持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第9天,点击查看活动详情
题目
给定两个大小相等的数组 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^5nums2.length == nums1.length0 <= nums1[i], nums2[i] <= 10^9
思考
本题难度中等。
首先是读懂题意。给定两个大小相等的数组 nums1 和 nums2,nums1 相对于 nums2 的优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描述。我们需要返回 nums1 的 任意排列,使其相对于 nums2 的优势最大化。
这是有意思的一道题,也可以看成是“田忌赛马”问题。
孙子曰:“今以君之下驷与彼上驷,取君上驷与彼中驷,取君中驷与彼下驷。”既驰三辈毕,而田忌一不胜而再胜,卒得王千金。
我们把 nums1 当成是田忌的马,nums2 当成是齐威王的马。我们将田忌的马按照从慢到快进行排序(也就是nums1从小到大进行排序)。
考虑田忌的下等马(nums1 的最小值):
-
如果它比齐威王的下等马(nums2 的最小值)快,那么胜出;
-
如果它比不过齐威王的下等马,则用该马与齐威王的上等马(nums2 的最大值)比。
去掉这两匹马,问题变成一个规模更小(n-1)的子问题。重复上述过程,即得到了所有马的对应关系。
代码实现时,由于 nums2 不能排序,我们可以创建一个下标数组 idxs,并对idxs 排序,即 idxs[0] 对应 nums2 中最小值的下标,idxs[1] 对应 nums2 中第二小值的下标,…。我们用双指针操作 idxs,从而知道每个下标所要对应的 nums1 的元素,也就找到了所要求的 nums1 的排列。
考虑到我们需要对数组nums1和数组idxs进行排序,因此时间复杂度是O(nlogn),空间复杂度是O(logn)。
解答
方法一:贪心算法(田忌赛马)
/**
* @param {number[]} nums1
* @param {number[]} nums2
* @return {number[]}
*/
var advantageCount = function(nums1, nums2) {
const n = nums1.length
const idx = []
for (let i = 0; i < n; ++i) {
idx[i] = i
}
idx.sort((i, j) => nums2[i] - nums2[j])
nums1.sort((i, j) => i - j)
// console.log(nums2, idx, nums1)
const ans = []
let left = 0, right = n - 1
for (let i = 0; i < n; ++i) {
if (nums1[i] > nums2[idx[left]]) {
ans[idx[left]] = nums1[i]
++left
} else {
ans[idx[right]] = nums1[i]
--right
}
}
return ans
}
// 执行用时:236 ms, 在所有 JavaScript 提交中击败了89.87%的用户
// 内存消耗:60.7 MB, 在所有 JavaScript 提交中击败了54.19%的用户
// 通过测试用例:67 / 67
复杂度分析:
- 时间复杂度:O(nlogn),其中 n 为数组 nums1 和 nums2 的长度。
- 空间复杂度:O(logn)。