持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第7天,点击查看活动详情
题目描述
给定两个大小相等的数组 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 <= 105
- nums2.length == nums1.length
- 0 <= nums1[i], nums2[i] <= 109
思路
经典的贪心题目,贪心题目的最重要特征就是,局部的最优解是全局最优解的一部分,即全局最优解的任何一个小部分单独拿出来看,也是最优解。本题可以用田忌赛马的思路来解决。对于nums2中的每个数,我们最划算的做法,是从nums1剩下的数字中,选取大于nums2[i]的最小的数来跟它配对,这样既能使得这一次对位有优势,又让剩下的数字尽可能有优势。如果当前不存在任何大于nums2[i]的数字了,那么就选取当前剩下最小的数去对位,这样在这1位无法有优势的情况下,尽量让剩下的数字优势最大,类似于用下等马去对上对方的上等马。快速找到大于nums2[i]的最小的数,可以使用treeset来解决。
Java版本代码
class Solution {
public int[] advantageCount(int[] nums1, int[] nums2) {
int len = nums2.length;
// 构建treeSet
TreeSet<Integer> treeSet = new TreeSet<>();
// 使用1个map来记录每个数字出现的次数
Map<Integer, Integer> cntMap = new HashMap<>();
for (int i : nums1) {
cntMap.put(i, cntMap.getOrDefault(i, 0) + 1);
if (cntMap.get(i) == 1) {
treeSet.add(i);
}
}
int[] ans = new int[len];
int index = 0;
for (int j : nums2) {
Integer min = treeSet.ceiling(j+1);
if (min == null) {
min = treeSet.ceiling(-1);
}
ans[index++] = min;
cntMap.put(min, cntMap.get(min) - 1);
if (cntMap.get(min) == 0) {
treeSet.remove(min);
}
}
return ans;
}
}