刷题的日常-优势洗牌

52 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第11天,点击查看活动详情

刷题的日常-2022年10月8号

一天一题,保持脑子清爽

优势洗牌

来自leetcode的 870 题,题意如下:

给定两个大小相等的数组nums1和nums2,nums1相对于 nums的优势可以用满足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]

理解题意

我们可以从题意中提取的条件如下:

  • 题目给出两个数组
  • 要求我们返回nums1的重排序
  • 要求nums1[i] > nums2[i]占大多数

做题思路

这道题让我想到了田忌赛马,其实就是用比较大的数去匹配刚刚好超过nums2中的数,抛弃掉比较小的数。规则如下:

  • 将两个数组进行排序
  • 从前往后遍历nums2
  • 在nums1中选出刚好超过nums2的第一个数,没有匹配的放入待匹配列表
  • 最后将待匹配理解放回数组中,这部分是不符合条件的

以上规则有个问题,就是需要对nums2进行排序,而题目不允许对nums2进行操作,所以我们可以开辟一个空间进行排序,步骤如下:

  • 开辟两个优先级队列对nums1和nums2进行排序
  • 再开辟个列表进行保存不能匹配的数
  • 将nums1和nums2进行排序,这里nums2的队列保存的是索引,但是排序规则还是按数的大小进行的
  • 对nums1的数逐个取出匹配,能够匹配到的放到nums1中对应的nums2的索引位置
  • 不匹配的放入最后的列表
  • 最后将剩下的数据放入未放置的地方即可

代码实现

代码实现如下:

public class Solution {
    public int[] advantageCount(int[] nums1, int[] nums2) {
        Queue<Integer> numQueue = new PriorityQueue<>();
        Queue<Integer> idxQueue = new PriorityQueue<>(Comparator.comparingInt(o -> nums2[o]));
        Queue<Integer> left = new LinkedList<>();
        for (int i = 0; i < nums1.length; i++) {
            numQueue.add(nums1[i]);
            idxQueue.add(i);
        }
        while (!numQueue.isEmpty()) {
            Integer num = numQueue.poll();
            int current = nums2[idxQueue.peek()];
            if (num > current) {
                nums1[idxQueue.poll()] = num;
                continue;
            }
            left.add(num);
        }
        while (!idxQueue.isEmpty()) {
            nums1[idxQueue.poll()] = left.poll();
        }
        return nums1;
    }
}

379cd8906470aa42af6733207fc093c.jpg