红包运气榜 | 豆包MarsCode AI刷题

78 阅读4分钟

题目

问题描述

小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;
 }

复杂度

时间复杂度

  1. 遍历输入数据并处理每个人的抢红包金额:

    在代码中,我们首先遍历输入的数组 sx,并在过程中计算每个人的总金额。由于 n 是输入的人员数量,因此这一部分的时间复杂度是:

    • 遍历每个人的红包金额:O(n)
    • 使用 unordered_map 查找和插入操作,平均时间复杂度为 O(1),因此在最坏情况下也可以看作是 O(n)

    所以,这一部分的时间复杂度为 O(n)

  2. 稳定排序操作:

    稳定排序(std::stable_sort)的时间复杂度通常是 O(n log n) ,因为它的实现通常基于归并排序或其他稳定排序算法。

    • 需要对 people 数组(包含 n 个元素)进行排序,排序依据是红包金额,并且保持相同金额的人按照他们的顺序排列。
    • 因此,这一部分的时间复杂度为 O(n log n)
  3. 构建返回的结果:

    最后,我们根据排好序的数据构建结果数组,提取每个人的名字。这个过程只需要遍历 k(即不同的名字个数),因此其时间复杂度为 O(k)

    但由于 k 最多为 n,因此这一部分的时间复杂度可以看作是 O(n)

综合时间复杂度

将上述步骤合并,整体时间复杂度为:

  • 遍历处理输入数据:O(n)
  • 稳定排序:O(n log n)
  • 构建返回结果:O(n)

因此,总体时间复杂度是 O(n log n)

空间复杂度

  1. 存储unordered_map 存储了每个人名字与其总金额的映射,最多存储 n 个元素,因此空间复杂度为 O(n)
  2. 存储 people 数组: 该数组包含 npair<string, int> 元素,因此空间复杂度为 O(n)
  3. 存储返回结果: 最后构建的返回结果数组最多包含 n 个元素,因此空间复杂度为 O(n)

因此,总体空间复杂度也是 O(n)

总结

  • 时间复杂度: O(n log n)
  • 空间复杂度: O(n)