870 优势洗牌(贪心)

1. 问题描述:

给定两个大小相等的数组 A 和 B,A 相对于 B 的优势可以用满足 A[i] > B[i] 的索引 i 的数目来描述。

返回 A 的任意排列,使其相对于 B 的优势最大化。

示例 1:

输入:A = [2,7,11,15], B = [1,10,4,11]
输出:[2,11,7,15]
示例 2:

输入:A = [12,24,8,32], B = [13,25,32,11]
输出:[24,32,8,12]

提示:

1 <= A.length = B.length <= 10000
0 <= A[i] <= 10^9
0 <= B[i] <= 10^9

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/advantage-shuffle

2. 思路分析:

① 首先需要理解清楚题目,可以知道我们需要求解的是使得A中元素与B中元素进行配对之后赢的最大可能性的组合是什么,返回的是与B中元素一一对应配对的A排列情况,其实简单来说就是就是我们之前听过的经典故事:田忌赛马,可以去百度百科查一下这些资料就很清楚题目表达的意思

② 这种题目很经典地让我们想到使用贪心的策略来做,我们希望使用这样一个策略,使得当前A中的元素尽可能大于当前B中的元素,假如当前的A中的元素不大于B中的元素,那么尝试A中的下一个元素与之前的B的元素进行匹配

③ 在官方提供的代码中其实还是比较好理解的,使用的就是这样的贪心策略,很值得学习,它的基本实现方法如下:

1)将A数组与B数组克隆出来,因为在最后的答案生成过程中需要使用到排序之前的数组,答案是根据之前的B数组的顺序来生成的

2)将克隆出来的A、B数组进行排序,排序之后很容易找到AB数组元素的大小关系,其中使用到了Map<Integer, Deque<Integer>>数据结构进行映射,键为当前B数组的元素值,值为当前与B数组进行匹配的A数组的元素值,为什么使用双端队列呢?因为数组的元素是有重复的所以可能存在着多个相同的元素(使用队列也行,只要满足先进先出的特点就可以),这个时候需要map进行映射的话假如值为普通的数据类型那么相同的键(B中存在相同的元素)的值就可能被覆盖掉,所以要使用队列来存储元素这样可以避免这个问题

3)使用一个变量来记录当前B数组中匹配的位置,在循环中遍历A数组,当A数组的元素大于了B数组的元素的时候,将当前匹配的元素映射到map中,B数组匹配的位置往下移动一位,假如不大于那么加入到另外一个队列之中,因为这些元素与B当前的元素是不匹配的,最好再处理这些在队列中不匹配的元素

4)最后在循环中检查map的映射关系,找到当前元素与B匹配的A中的元素是什么,遍历的过程生成排列情况,其实整个过程还是比较好理解的,最好的话借助于debug调试一下,这样会更容易理解其中的过程

3. 代码如下:

官方的代码如下:

class Solution {
    public int[] advantageCount(int[] A, int[] B) {
        int[] sortedA = A.clone();
        Arrays.sort(sortedA);
        int[] sortedB = B.clone();
        Arrays.sort(sortedB);
        Map<Integer, Deque<Integer>> assigned = new HashMap();
        for (int b: B) assigned.put(b, new LinkedList());
        Deque<Integer> remaining = new LinkedList();
        int j = 0;
        for (int a: sortedA) {
            if (a > sortedB[j]) {
                assigned.get(sortedB[j++]).add(a);
            } else {
                remaining.add(a);
            }
        }
        int[] ans = new int[B.length];
        for (int i = 0; i < B.length; ++i) {
            if (assigned.get(B[i]).size() > 0)
                ans[i] = assigned.get(B[i]).pop();
            else
                ans[i] = remaining.pop();
        }
        return ans;
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值