Q870 优势洗牌(田忌赛马) Q870 优势洗牌(田忌赛马)

题目描述

Q870 优势洗牌(田忌赛马)
Q870 优势洗牌(田忌赛马)

通过题目描述,我们很容易联想到田忌赛马的故事。

第一种解题思路(超时)

我在思考这道题的时候,想到直接将nums1数组升序排列得到clone,然后将clone数组从小到大和nums2中的数进行对,如果clone中有数大于nums2[i],就将这个数赋值给nums1[i],如果找遍clone都没有找到大于nums2[i]的数,则用list记录下下标index,然后用clone中剩余的数挨个赋值给nums[index];

 public int[] advantageCount(int[] nums1, int[] nums2) {
         ArrayList<Integer> clone = new ArrayList<>();
        int n = nums1.length;
        for (int i = 0; i < n; i++) {
            clone.add(nums1[i]);
        }
        Collections.sort(clone);
        List<Integer> index = new ArrayList<>();
        L:
        for (int i = 0; i < n; i++) {
            for (int num : clone) {
                if (num > nums2[i]) {
                    nums1[i] = num;
                    clone.remove(Integer.valueOf(num));
                    continue L;
                }
            }
            index.add(i);
        }
        if (!clone.isEmpty()) {
            int size = clone.size();
            for (int i = 0; i < size; i++) {
                nums1[index.get(i)] = clone.get(i);
            }
        }
        return nums1;
    }

超时原因(时间复杂度分析):

这种算法施加复杂度为O(n2),for循环嵌套for循环。(Collection.sort()的时间复杂度为nlogn)造成的原因是未对nums2进行排序,导致了对每一个nums2的数,都需要遍历nums1,虽然题目要求nums2的顺序不能改变,但是如果不对nums2进行排序的话,肯定会超时。

优先队列+双指针

我们使用优先队列加双指针的方式,先对nums1和nums2进行排序,这里我们使用在优先队列中使用int[]数组来记录nums2[i]的值和下标i,然后对nums2[i]进行降序排列。

 PriorityQueue<int[]> pq = new PriorityQueue<>((a, b) -> (b[1] - a[1]));
        int n = nums2.length;
        for (int i = 0; i < n; i++) {
            pq.add(new int[]{i, nums2[i]});
        }
        Arrays.sort(nums1);
        int l = 0, r = n - 1;
        int[] res = new int[n];
        while (!pq.isEmpty()) {
            int[] pair = pq.poll();
            if (nums1[r] > pair[1]) {
                res[pair[0]] = nums1[r];
                r--;
            } else {
                res[pair[0]] = nums1[l];
                l++;
            }
        }
        return res;

然后我们对nums1进行降序排列。

随后,我们用两个指针l,r分别指向nums1的开始和结尾。

这里必须要说明的是,我们用nums1的最大的数和nums2最大的数比较,会有两种情况:

1、如果nums1最大的数大于nums2最大的数(田忌的上等马跑过齐王的上等马):

则让index=pq.poll()[0];使res[index]=nums1[r];

2、如果nums1最大的数小于nums2最大的数:则找个下等马(nums1最小的数)去送,使res[index]=nums1[l](nums1[l]是nums1数组中最小的数);

时间复杂度分析:

很好分析;优先队列排序的时间复杂度为nlogn,算主体的复杂度为滑动窗口的复杂度O(n),所以总体来说复杂度为nlogn。