【3.5】贪心算法-解优势洗牌(类田忌赛马问题)

一、问题

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

二、解题思路

这个问题要求我们重新排列数组A,使得在相同位置上,数组A的元素大于数组B的元素的次数最多,从而最大化数组A相对于数组B的优势。我们可以将数组A视为田忌的马匹,数组B视为齐王的马匹,数组中的数值代表马匹的速度。

对于任意长度的数组,我们可以采用类似田忌赛马的策略来解决这个问题:

  1. **如果田忌最快的马速度不及齐王最快的马**,那么田忌应该用最慢的马与齐王最快的马比赛。因为齐王最快的马已经超过了田忌最快的马,田忌无论派出哪匹马都会输,所以选择用最慢的马来节省实力。

  2. **如果田忌最快的马速度超过齐王最快的马**,那么田忌应该用最快的马与齐王最快的马比赛。因为田忌最快的马能够赢得这场比赛,所以应该充分利用这匹马的优势。

这种策略的合理性在于,通过比较田忌和齐王最快的马,我们可以决定是否值得用田忌最快的马去争取胜利。如果田忌最快的马无法胜过齐王最快的马,那么使用最慢的马是明智的选择,因为这样可以保留更强的马匹用于后续的比赛。反之,如果田忌最快的马能够胜过齐王最快的马,那么就应该用它来确保这场比赛的胜利。

通过这种贪心算法的策略,我们可以在每一步都做出当前最优的选择,从而最大化数组A相对于数组B的优势。

三、代码实现

原理已经了解,我们来看下代码

cpp 复制代码
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

std::vector<int> advantageCount(std::vector<int>& nums1, std::vector<int>& nums2) {
    int length = nums1.size();
    std::vector<int> res(length);
    // 先对数组nums1从小到大进行排序
    std::sort(nums1.begin(), nums1.end());
    // 对数组nums2从大到小排序,这里使用的是优先队列,也就是最大堆,每次出队的都是堆中最大的元素
    // 这里存储的是数组nums2中的元素和元素对应的下标
    std::priority_queue<std::pair<int, int>> pq;
    for (int i = 0; i < length; i++) {
        pq.push({nums2[i], i});
    }
    // 双指针,分别指向数组nums1中的最小值和最大值。可以类比于田忌跑的最慢的马和跑的最快的马
    int left = 0;
    int right = length - 1;
    while (!pq.empty()) {
        // 队列中存放的是数组nums2中的元素,每次出队的都是堆中最大的值,
        // 类比齐王每次都拿出剩下的马中最好的马比赛
        auto cur = pq.top();
        pq.pop();
        int index = cur.second;
        int val = cur.first;
        // 先用nums1中的最大值和nums2中的最大值比较,类似于田忌用最好的马
        // 和齐王最好的马比较,如果田忌最好的马跑的比齐王最好的马跑的快,
        // 就用田忌最好的马和齐王最好的马比赛
        if (nums1[right] > val) {
            res[index] = nums1[right--];
        } else {
            // 如果田忌最好的马没有齐王最好的马跑的快,就用田忌最差的马
            // 和齐王最好的马比赛
            res[index] = nums1[left++];
        }
    }
    return res;
}

int main() {
    std::vector<int> nums1 = {2, 7, 11, 15};
    std::vector<int> nums2 = {1, 10, 4, 11};
    std::vector<int> result = advantageCount(nums1, nums2);
    for (int num : result) {
        std::cout << num << " ";
    }
    std::cout << std::endl;
    return 0;
}
相关推荐
谷雨不太卷4 小时前
进程的状态码
java·前端·算法
顾温4 小时前
default——C#/C++
java·c++·c#
凉茶钱5 小时前
【c语言】动态内存管理:malloc,calloc,realloc,柔性数组
c语言·c++·vscode·柔性数组
脏脏a5 小时前
【C++模版】泛型编程:代码复用的终极利器
开发语言·c++·c++模版
island13145 小时前
【C++仿Muduo库#3】Server 服务器模块实现上
服务器·开发语言·c++
散峰而望5 小时前
【算法竞赛】C/C++ 的输入输出你真的玩会了吗?
c语言·开发语言·数据结构·c++·算法·github
小龙报5 小时前
【C语言】内存里的 “数字变形记”:整数三码、大小端与浮点数存储真相
c语言·开发语言·c++·创业创新·学习方法·visual studio
躺不平的理查德5 小时前
时间复杂度与空间复杂度备忘录
数据结构·算法
yaki_ya5 小时前
yaki-C语言:从概念基础到内存解析---数组(array)完全指南
java·c语言·算法
刃神太酷啦5 小时前
扒透 STL 底层!map/set 如何封装红黑树?迭代器逻辑 + 键值限制全手撕----《Hello C++ Wrold!》(23)--(C/C++)
java·c语言·javascript·数据结构·c++·算法·leetcode