题目
问题描述
小C参与了一场抢红包的游戏,现在他想要对所有参与抢红包的人进行一次运气排名。排名规则如下:抢到的金额越多,排名越靠前;如果两个人抢到的金额相同,则按照他们抢红包的顺序进行排名。比如,如果小C和小U抢到的金额相同,但小C比小U先抢,则小C排在小U前面。
测试样例
样例1:
输入:
n = 4 ,s = ["a", "b", "c", "d"] ,x = [1, 2, 2, 1]输出:['b', 'c', 'a', 'd']
样例2:
输入:
n = 3 ,s = ["x", "y", "z"] ,x = [100, 200, 200]输出:['y', 'z', 'x']
样例3:
输入:
n = 5 ,s = ["m", "n", "o", "p", "q"] ,x = [50, 50, 30, 30, 20]输出:['m', 'n', 'o', 'p', 'q']
解析
关于排序的处理。
由题目可知,我们应该把人名和金额关联起来,可以利用结构体等方式把这两个数据打包在一起,在这里我用的是pair<string, int>,把这些变量存入数组中。
因为题目中可能会多次出现同一个名字,对于重复出现的名字,我们需要把金额相加。因此使用map记录每个名字第一次在数组中出现的下标,遇到重复的名字,就可以直接通过map定位到它在数组中的位置,进行金额的相加。
最后,排序规则为:抢到的金额越多,排名越靠前;如果两个人抢到的金额相同,则按照他们抢红包的顺序进行排名。
因此我们将数组按照金额从大到小排,且必须是个稳定排序,即不改变金额相同的两人的相对前后位置。
Code
#include <iostream>
#include <utility>
#include <vector>
#include <string>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef std::pair<string, int> PSI;
vector<string> solution(int n, vector<string> s, vector<int> x) {
std::vector<PSI> people;
std::unordered_map<std::string, int> mp;
int k = 0;
for (int i = 0; i < n; i++) {
if (mp.find(s[i]) == mp.end()) {
mp[s[i]] = k++;
people.push_back({s[i], x[i]});
}
else {
people[mp[s[i]]].second += x[i];
}
}
std::stable_sort(people.begin(), people.end(), [](const auto& a, const auto& b){ return a.second > b.second; });
std::vector<string> ans(k);
for (int i = 0; i < k; i++) ans[i] = people[i].first;
return ans;
}
int main() {
cout << (solution(4, {"a", "b", "c", "d"}, {1, 2, 2, 1}) == vector<string>{"b", "c", "a", "d"}) << endl;
cout << (solution(3, {"x", "y", "z"}, {100, 200, 200}) == vector<string>{"y", "z", "x"}) << endl;
cout << (solution(5, {"m", "n", "o", "p", "q"}, {50, 50, 30, 30, 20}) == vector<string>{"m", "n", "o", "p", "q"}) << endl;
cout << (solution(6, {"a", "b", "a", "c", "b", "a"}, {10, 20, 5, 15, 10, 10}) == vector<string>{"b", "a", "c"}) << endl;
return 0;
}
复杂度
时间复杂度
-
遍历输入数据并处理每个人的抢红包金额:
在代码中,我们首先遍历输入的数组
s和x,并在过程中计算每个人的总金额。由于n是输入的人员数量,因此这一部分的时间复杂度是:- 遍历每个人的红包金额:
O(n)。 - 使用
unordered_map查找和插入操作,平均时间复杂度为O(1),因此在最坏情况下也可以看作是O(n)。
所以,这一部分的时间复杂度为 O(n) 。
- 遍历每个人的红包金额:
-
稳定排序操作:
稳定排序(
std::stable_sort)的时间复杂度通常是 O(n log n) ,因为它的实现通常基于归并排序或其他稳定排序算法。- 需要对
people数组(包含n个元素)进行排序,排序依据是红包金额,并且保持相同金额的人按照他们的顺序排列。 - 因此,这一部分的时间复杂度为 O(n log n) 。
- 需要对
-
构建返回的结果:
最后,我们根据排好序的数据构建结果数组,提取每个人的名字。这个过程只需要遍历
k(即不同的名字个数),因此其时间复杂度为 O(k) 。但由于
k最多为n,因此这一部分的时间复杂度可以看作是 O(n) 。
综合时间复杂度
将上述步骤合并,整体时间复杂度为:
- 遍历处理输入数据:O(n)
- 稳定排序:O(n log n)
- 构建返回结果:O(n)
因此,总体时间复杂度是 O(n log n) 。
空间复杂度
- 存储
unordered_map: 存储了每个人名字与其总金额的映射,最多存储n个元素,因此空间复杂度为 O(n) 。 - 存储
people数组: 该数组包含n个pair<string, int>元素,因此空间复杂度为 O(n) 。 - 存储返回结果: 最后构建的返回结果数组最多包含
n个元素,因此空间复杂度为 O(n) 。
因此,总体空间复杂度也是 O(n) 。
总结
- 时间复杂度: O(n log n)
- 空间复杂度: O(n)