LeetCode 0870. 优势洗牌 - LetMeFly趣解田忌赛马:能赢则赢,否则摆烂(贪心)

Posted Tisfy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 0870. 优势洗牌 - LetMeFly趣解田忌赛马:能赢则赢,否则摆烂(贪心)相关的知识,希望对你有一定的参考价值。

【LetMeFly】趣解田忌赛马:能赢则赢,否则摆烂(贪心) - 870.优势洗牌

力扣题目链接:https://leetcode.cn/problems/advantage-shuffle/

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

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

 

示例 1:

输入:nums1 = [2,7,11,15], nums2 = [1,10,4,11]
输出:[2,11,7,15]

示例 2:

输入:nums1 = [12,24,8,32], nums2 = [13,25,32,11]
输出:[24,32,8,12]

 

提示:

  • 1 <= nums1.length <= 105
  • nums2.length == nums1.length
  • 0 <= nums1[i], nums2[i] <= 109

方法一:田忌赛马(贪心)

思路很简单,就是:

从对手战力最弱的🐎开始,每次从 自己未出场 且 战力大于对手的这匹🐎 的🐎中,挑选战力最小的一匹。
若无🐎可敌,则开始摆烂

举个例子,假如自己的五匹马的战力为12、24、8、32、6,对手的五匹马的战力为13、25、32、11、998

从对手的战力最弱的🐎开始,先看对手战力为11的🐎,再看战力为13的🐎,再看25,再看32,最后看998

  1. 对于对手的11,自己的🐎中,未出场 且 战力大于11的有12、24、32,其中战力最小的是12,因此选派自己的12对抗对手的11
  2. 对于对手的13,自己的🐎中,未出场 且 战力大于13的有24、32,其中战力最小的是24,因此选派自己的24对抗对手的13
  3. 对于对手的25,自己的🐎中,未出场 且 战力大于25的有32,其中战力最小的是32,因此选派自己的32对抗对手的25
  4. 对于对手的32,自己的🐎中,没有 未出场 且 战力大于32的🐎,无🐎可敌,开始摆烂!

怎么摆烂呢?反正也赢不了了,那么就在自己未出场的🐎中随便上吧!上谁都无所谓,反正也赢不了。

对面还有两匹马32、998没有对手,自己还有两匹马8、6没有出场。那就用自己的8对抗对手的32,自己的6对抗对手的998好了。

因此,对于对手的出场顺序(数组2)[13, 25, 32, 11, 998],我们的回敬(打乱的数组1)是:[24, 32, 8, 12, 6]

能胜三场,还行还行。

那么编程怎么实现呢?

其实不难发现,我们在挑选对手和自己的🐎时,在背后默默进行了排序操作。

我们将对手的[13, 25, 32, 11, 998]默默排序成了[11, 13, 25, 32, 998]作为出场顺序;我们将自己的[12, 24, 8, 32, 6]默默排序成了[6, 8, 12, 24, 32]以方便选取“大于敌方且尽可能小”的🐎。

但是需要注意的是,对手的马匹排序后,原始顺序不能丢失,因为我们默默地将对手马匹按战力排序了,对手可不会因为你的排序而改变自己的出场顺序。

因此,在对对手的马匹进行排序前,不如先做个手脚:将对手的<马匹战力, 出场编号>进行绑定,依据战力排序,排序后出厂编号信息不会丢失。

至于自己的🐎,用一个“指针”记录当前判断到了哪一匹,如果这一匹马的战力不大于当前遍历到的对手的🐎的战力,就指针后移,找到第一个大于对手战力的位置,就是自己“未出场 且 战力大于对手”的🐎中,战力最小的那匹。 (若自己这匹马战力不足,那么指针后移之前,记得将这匹马标记或者存起来,表示“指针扫过了但是未出场”,以到最后和敌方的“无敌之🐎”进行摆烂)

  • 时间复杂度 O ( n log ⁡ n ) O(n\\log n) O(nlogn),其中 n n n是马匹个数。排序的时间复杂度是 O ( n log ⁡ n ) O(n\\log n) O(nlogn),选马的时间复杂度是 O ( n ) O(n) O(n)
  • 空间复杂度 O ( n ) O(n) O(n)。我们使用了额外的空间来记录对手马匹的“出场编号”信息( O ( n ) O(n) O(n)),且使用了额外空间记录了自己“指针扫过但因战力不足而未出场的🐎”( O ( n ) O(n) O(n));排序的空间复杂度是 O ( log ⁡ n ) O(\\log n) O(logn)

AC代码

C++

typedef pair<int, int> pii;  // <战力, 出场编号>
class Solution 
public:
    vector<int> advantageCount(vector<int>& nums1, vector<int>& nums2) 
        int n = nums1.size();
		// 记录对手(nums2)出场顺序信息
        vector<pii> tempNums2(n);
        for (int i = 0; i < n; i++) 
            tempNums2[i] = nums2[i], i;
        
		// 对对手、自己马匹排序
        sort(tempNums2.begin(), tempNums2.end());
        sort(nums1.begin(), nums1.end());

        vector<int> ans(n);  // ans存放最终答案
        int loc1 = 0;  // 自己的马匹的“指针”
        vector<int> unused;  // 指针扫过但未出场的马,留着摆烂使用
        for (int i = 0; i < n; i++)   // 遍历对手马
            while (loc1 < n && nums1[loc1] <= tempNums2[i].first)   // 自己的马战力不足
                unused.push_back(nums1[loc1]);  // 放入“未使用数组”
                loc1++;  // 指针后移
            
            if (loc1 == n)   // 指针到数组尾部,扫描完毕,无高战力马可出场,开始摆烂,摆烂完退出循环
                int locUnused = 0;  // 为了遍历“未使用数组”
                while (i < n)   // 为后面所有的“对手无敌马”分配自己的“摆烂马”
                    ans[tempNums2[i++].second] = unused[locUnused++];
                
                break;  // 摆烂完退出循环
            
            ans[tempNums2[i].second] = nums1[loc1++];  // 为对手的彼马分配自己的 未使用且战力更强 的战力尽可能小马
        
        return ans;
    
;

同步发文于CSDN,原创不易,转载请附上原文链接哦~
Tisfy:https://letmefly.blog.csdn.net/article/details/127207642

以上是关于LeetCode 0870. 优势洗牌 - LetMeFly趣解田忌赛马:能赢则赢,否则摆烂(贪心)的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode 870. 优势洗牌(田忌赛马问题)

LeetCode 870 优势洗牌[自定义排序] HERODING的LeetCode之路

LeetCode 870 优势洗牌[自定义排序] HERODING的LeetCode之路

LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)

LeetCode 870. 优势洗牌(根据数值对索引排序)/ 856. 括号的分数(栈) / 801. 使序列递增的最小交换次数(动态规划)

力扣 每日一题 870. 优势洗牌难度:中等(贪心+双指针)