英雄决斗比赛的胜利最大化
题目分析
小U和小F正在进行多轮决斗,每轮比赛各自派出英雄对决。小U的出场顺序固定为 1, 2, 3, ..., n,小F可以自由调整出场顺序,目标是使小F的胜利轮数尽可能多。
问题的关键是,小F需要找到一种英雄出场顺序,使得在尽可能多的轮次中,他的英雄能力值高于小U的英雄。
解题思路
我们可以将问题转化为一个双指针的排序匹配问题:
- 排序:先将小F的英雄能力值排序(从小到大),同时小U的英雄能力值已天然按照从小到大的顺序排列。
- 双指针模拟比赛:利用两个指针分别指向小U和小F当前的英雄出场位置,根据比赛结果调整指针和胜利计数:
- 若小F的当前英雄能力值 大于 小U的当前英雄能力值,小F胜利,双方指针向后移动。
- 若小F的当前英雄能力值 小于等于 小U的当前英雄能力值,则小F需要放弃当前英雄,用该英雄来消耗小U较弱的英雄,并移动相应指针。
算法步骤
- 将小F的英雄能力值数组
heroes排序。 - 初始化两个指针:
la和lb分别指向小U和小F的最左端;ra和rb分别指向小U和小F的最右端。 - 模拟比赛过程:
- 若
heroes[rb] > u_heroes[ra],小F胜利,右端指针均左移。 - 若
heroes[rb] <= u_heroes[ra],尝试匹配小U最弱的英雄:- 若
heroes[lb] > u_heroes[la],小F胜利,左端指针均右移。 - 否则,小F的当前最弱英雄无法获胜,
lb右移,小U的最强英雄被消耗,ra左移。
- 若
- 若
代码实现
以下为完整代码:
#include <bits/stdc++.h>
using namespace std;
int solution(int number, std::vector<int> heroes) {
int res = 0;
sort(heroes.begin(), heroes.end());
vector<int> u_heroes(number);
for (int i = 0; i < number; ++i) {
u_heroes[i] = i + 1;
}
int la = 0, lb = 0, ra = number - 1, rb = number - 1;
while (la <= ra && lb <= rb) {
if (heroes[rb] > u_heroes[ra]) { // 小F的最强英雄击败小U的最强英雄
++res;
--rb;
--ra;
} else if (heroes[rb] < u_heroes[ra]) { // 小F的最强英雄无法胜利,消耗小U的最强英雄
++lb;
--ra;
} else { // 小F的最强英雄与小U的最强英雄能力相等,尝试用小F的最弱英雄击败小U的最弱英雄
if (heroes[lb] > u_heroes[la]) {
++res;
++lb;
++la;
} else {
++lb;
--ra;
}
}
}
return res;
}
int main() {
std::vector<int> heroes1 = {10,1,1,1,5,5,3};
std::vector<int> heroes2 = {1,1,1,1,1};
std::vector<int> heroes3 = {1,2,3,4,5,6,7,8,9,10};
std::cout << (solution(7, heroes1) == 4) << std::endl;
std::cout << (solution(5, heroes2) == 0) << std::endl;
std::cout << (solution(10, heroes3) == 9) << std::endl;
return 0;
}
复杂度分析
- 时间复杂度:
- 排序:
O(n log n)。 - 双指针匹配:
O(n)。 总时间复杂度为O(n log n)。
- 排序:
- 空间复杂度:
- 使用了两个数组存储小U和小F的英雄队伍,空间复杂度为
O(n)。
- 使用了两个数组存储小U和小F的英雄队伍,空间复杂度为
测试样例
-
样例1:
输入:heroes = [10,1,1,1,5,5,3], number = 7
输出:4
解释:调整后小F的最佳顺序为[10,5,5,3,1,1,1],分别胜利 4 轮。 -
样例2:
输入:heroes = [1,1,1,1,1], number = 5
输出:0
解释:小F的英雄均不可能胜利。 -
样例3:
输入:heroes = [1,2,3,4,5,6,7,8,9,10], number = 10
输出:9
解释:小F可以通过调整顺序击败小U的所有英雄(除能力值为 10 的英雄)。
总结
本题的核心在于利用排序和双指针的贪心策略,最大化小F的胜利轮数。通过合理的匹配策略,我们确保每一次出场都尽可能多地消耗小U的强力英雄,或者保留小F的胜利可能性。