Given two arrays `A` and `B` of equal size, the *advantage of `A` with respect to `B`* is the number of indices `i` for which `A[i] > B[i]`.

Return any permutation of A that maximizes its advantage with respect to B.

Example 1:

Input: A = [2,7,11,15], B = [1,10,4,11]
Output: [2,11,7,15]

Example 2:

Input: A = [12,24,8,32], B = [13,25,32,11]
Output: [24,32,8,12]

Note:

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

这道题给了我们两个数组A和B,让对A进行重排序,使得每个对应对位置上A中的数字尽可能的大于B。这不就是大名鼎鼎的田忌赛马么,但想出高招并不是田忌,而是孙膑,就是孙子兵法的作者,但这 credit 好像都给了田忌,让人误以为是田忌的智慧,不禁想起了高富帅重金买科研成果的冠名权的故事。孙子原话是,“今以君之下驷与彼上驷,取君上驷与彼中驷,取君中驷与彼下驷”。就是自己的下马跟人上马比,稳输不用管,上马跟其中马跑,稳赢,中马跟其下马跑,还是稳赢。那我还全马跟其半马跑,能赢否?不过说的,今天博主所在的城市还真有马拉松比赛,而且博主还报了半马,但是由于身不由己的原因无法去跑,实在是可惜,没事,来日方长,总是有机会的。扯了这么久的犊子,赶紧拉回来做题吧。其实这道题的思路还真是田忌赛马的智慧一样,既然要想办法大过B中的数,那么对于B中的每个数(可以看作每匹马),先在A中找刚好大于该数的数字(这就是为啥中马跟其下马比,而不是上马跟其下马比),用太大的数字就浪费了,而如果A中没有比之大的数字,就用A中最小的数字(用下马跟其上马比,不过略有不同的是此时我们没有上马)。就用这种贪婪算法的思路就可以成功解题了,为了方便起见,就是用一个 MultiSet 来做,相当于一个允许重复的 TreeSet,既允许重复又自带排序功能,岂不美哉!那么遍历B中每个数字,在A进行二分搜索第一个大于的数字,这里使用了 STL 自带的 upper_bound 来做,当然想自己写二分也没问题。然后看,若不存在,则将A中最小的数字加到结果 res 中,否则就将第一个大于的数字加入结果 res 中,参见代码如下:


解法一:

class Solution {
public:
vector<int> advantageCount(vector<int>& A, vector<int>& B) {
vector<int> res;
multiset<int> st(A.begin(), A.end());
for (int i = 0; i < B.size(); ++i) {
auto it = (*st.rbegin() <= B[i]) ? st.begin() : st.upper_bound(B[i]);
res.push_back(*it);
st.erase(it);
}
return res;
}
};

当两个数组都是有序的时候,我们就能快速的直到各自的最大值与最小值,问题就变得容易很多了。比如可以先从B的最大值开始,这是就看A的最大值能否大过B,能的话,就移动到对应位置,不能的话就用最小值,然后再看B的次大值,这样双指针就可以解决问题。所以可以先给A按从小到大的顺序,对于B的话,不能直接排序,因为这样的话原来的顺序就完全丢失了,所以将B中每个数字和其原始坐标位置组成一个 pair 对儿,加入到一个最大堆中,这样B中的最大值就会最先被取出来,再进行上述的操作,这时候就可以发现保存的原始坐标就发挥用处了,根据其坐标就可以直接更新结果 res 中对应的位置了,参见代码如下:


解法二:

class Solution {
public:
vector<int> advantageCount(vector<int>& A, vector<int>& B) {
int n = A.size(), left = 0, right = n - 1;
vector<int> res(n);
sort(A.begin(), A.end());
priority_queue<pair<int, int>> q;
for (int i = 0; i < n; ++i) q.push({B[i], i});
while (!q.empty()) {
int val = q.top().first, idx = q.top().second; q.pop();
if (A[right] > val) res[idx] = A[right--];
else res[idx] = A[left++];
}
return res;
}
};

Github 同步地址:

https://github.com/grandyang/leetcode/issues/870

参考资料:

https://leetcode.com/problems/advantage-shuffle/

https://leetcode.com/problems/advantage-shuffle/discuss/149831/C%2B%2B-6-lines-greedy-O(n-log-n)

https://leetcode.com/problems/advantage-shuffle/discuss/149822/JAVA-Greedy-6-lines-with-Explanation

[LeetCode All in One 题目讲解汇总(持续更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)

[LeetCode] Advantage Shuffle 优势洗牌的更多相关文章

  1. Leetcode 870. 优势洗牌

    870. 优势洗牌  显示英文描述 我的提交返回竞赛   用户通过次数49 用户尝试次数92 通过次数49 提交次数192 题目难度Medium 给定两个大小相等的数组 A 和 B,A 相对于 B 的 ...

  2. Shuffle(洗牌)

    Shuffle(洗牌)    图    map        1.Map Task的输出k v,一开始会进入溢写缓冲区中,对数据做处理,比如分区.排序等操作.        2.有几个Map Task ...

  3. 文本数据挖掘---课后作业shuffle函数洗牌C++

    题目: 代码如下:#include <iostream> #include <random> #include <algorithm> #include <v ...

  4. [CareerCup] 18.2 Shuffle Cards 洗牌

    18.2 Write a method to shuffle a deck of cards. It must be a perfect shuffle—in other words, each of ...

  5. 闲话shuffle(洗牌)算法

    工作中经常会用到洗牌算法,看到这篇文章不错,原文摘自:http://www.atatech.org/article/detail/11821/928  作者:子仲   场景 洗牌算法的应用场景其实很多 ...

  6. uva 10710 - Chinese Shuffle(完美洗牌)

    option=com_onlinejudge&Itemid=8&category=474&page=show_problem&problem=1651"> ...

  7. 2.1 shuffle sort(洗牌)

    1.目的:将数组以随机的顺序重新排序,类似洗牌的过程 2.用途用于快速排序或者任何以划分为基础的排序中,目的是减少最坏可能性发生的概率. 3.想法1:给数组的每一个元素产生一个随机的数字作为键,然后使 ...

  8. [Swift]LeetCode870. 优势洗牌 | Advantage Shuffle

    Given two arrays A and B of equal size, the advantage of A with respect to B is the number of indice ...

  9. LeetCode 中级 - 优势洗牌(870)

    给定两个大小相等的数组 A 和 B,A 相对于 B 的优势可以用满足 A[i] > B[i] 的索引 i 的数目来描述. 返回 A 的任意排列,使其相对于 B 的优势最大化. 示例 2: 输入: ...

随机推荐

  1. Cocoapods安装 2018-11-01更新

    2018-11-1 更新 pod install 报错 [!] Oh no, an error occurred.   Cocoapods 需要更新 主要涉及2点内容 一.ruby 更新(V2.5.3 ...

  2. sql 常见错误总结

    1.根据一张表更新另一张表的数据. . 写法轻松,更新效率高: update table1 set field1=table2.field1, field2=table2.field2 from ta ...

  3. 【easy】257. Binary Tree Paths 二叉树找到所有路径

    http://blog.csdn.net/crazy1235/article/details/51474128 花样做二叉树的题……居然还是不会么…… /** * Definition for a b ...

  4. C# 登陆验证码工具类VerifyCode

    using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; ...

  5. python正则表达式--flag修饰符、match对象属性

    正则表达式—修饰符 正则表达式可以包含一些标志修饰符来控制匹配模式,用在正则表达式处理函数中的flag参数中,为可选参数. (1) re.I 全写(re.IGNORECASE) 表示使匹配时,忽略大小 ...

  6. 详解PROTOCOL BUFFERS

    1. 前言 Protocal Buffers是google推出的一种序列化协议.由于它的编码和解码的速度,已经编码后的大小控制的较好,因此它常常被用在RPC调用中,传递参数和结果.比如gRPC. Pr ...

  7. win10下caffe安装与mnist测试实验注意点

    caffe安装 安装内容:win10教育版+anaconda2+python(无gpu版本) 安装教程:主要依照三年一梦教程:https://www.cnblogs.com/king-lps/p/65 ...

  8. Ajax原理一篇就够了

    Ajax原理一篇就够了 一.什么是Ajax Ajax(Asynchronous JavaScript and XML的缩写)是一种异步请求数据的web开发技术,对于改善用户的体验和页面性能很有帮助.简 ...

  9. 4.2 Oracle Dataguard failover 操作步骤

    在11g里面,Oracle认为最理想的情况是,虽然Oracle数据库不能打开,但是可以启动到 mount状态.Mount状态之所以重要,就在于如果可以到这个阶段,控制文件control_file就可以 ...

  10. SQLAlchemy使用介绍

    SQLAlchemy is the Python SQL toolkit and Object Relational Mapper that gives application developers ...