Leetcode 870. 优势洗牌(中等) 田忌赛马策略

labuladong讲解

870. 优势洗牌(中等)

题目:

给你输入两个长度相等的数组 nums1 和 nums2,请你重新组织 nums1 中元素的位置,使得 nums1 的「优势」最大化。

如果 nums1[i] > nums2[i],就是说 nums1 在索引 i 上对 nums2[i] 有「优势」。优势最大化也就是说让你重新组织 nums1,尽可能多的让 nums[i] > nums2[i]

比如输入:

nums1 = [12,24,8,32] nums2 = [13,25,32,11]

你的算法应该返回 [24,32,8,12],因为这样排列 nums1 的话有三个元素都有「优势」。

思路:

我们暂且把田忌的一号选手称为 T1,二号选手称为 T2,齐王的一号选手称为 Q1

如果 T2 能赢 Q1,你试图保存己方实力,让 T2 去战 Q1,把 T1 留着是为了对付谁?

显然,你担心齐王还有战力大于 T2 的马,可以让 T1 去对付。

但是你仔细想想,现在 T2 已经是可以战胜 Q1 的,Q1 可是齐王的最快的马耶,齐王剩下的那些马里,怎么可能还有比 T2 更强的马?

所以,没必要节约,最后我们得出的策略就是:

将齐王和田忌的马按照战斗力排序,然后按照排名一一对比。如果田忌的马能赢,那就比赛,如果赢不了,那就换个垫底的来送人头,保存实力。

 

将nums1从大到小排序,按照num2从大到小的顺序,逐个比较num1对应位置的大小,如果nums1[left]>nums2,就设为left值,否则设为right值(最小值)

 

class Solution {
public:
    vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) {
        //记录nums2的值及位置
        priority_queue<Node> q;
        for(int i=0;i<nums2.size();++i){
            q.push(Node(i,nums2[i]));
        }
        //nums1从大到小排序
        sort(nums1.begin(),nums1.end(),[](int a,int b){
            return a>b;
        });
        //使用双指针记录nums1的最大值和最小值
        int left=0,right=nums1.size()-1;
        vector<int> ret(nums1.size());
        for(int i=0;i<nums1.size();++i){
            Node node=q.top();
            q.pop();
            int val=node.val;
            int id=node.id;
            //如果nums1对应位置大于nums2,设为该值
            if(nums1[left]>val){
                ret[id]=nums1[left++];
            }else{
                //如果小于,则设为nums1的最小值
                ret[id]=nums1[right--];
            }
        }
        return ret;
    }
    struct Node{
        int id;
        int val;
        Node(int i,int v){
            id=i;
            val=v;
        }
        //priority_queue默认为大根堆,因此使用less来比较
        bool operator<(const Node& b) const{
            return val<b.val;
        }
    };
};

 

posted @ 2022-02-28 12:53  鸭子船长  阅读(306)  评论(0编辑  收藏  举报