统计班级中的说谎者|豆包MarsCode AI刷题

108 阅读3分钟

问题描述

在小C的班级里,有NN个学生,每个学生的成绩是AiA_i。小C发现了一件有趣的事:当且仅当某个学生的成绩小于或等于自己的有更多人时,这个学生会说谎。换句话说,如果分数小于等于他的学生数量大于比他分数高的学生数量,则他会说谎。

现在,小C想知道班里有多少个学生会说谎。


测试样例

样例1:

输入:A = [100, 100, 100]
输出:3

样例2:

输入:A = [2, 1, 3]
输出:2

样例3:

输入:A = [30, 1, 30, 30]
输出:3

样例4:

输入:A = [19, 27, 73, 55, 88]
输出:3

样例5:

输入:A = [19, 27, 73, 55, 88, 88, 2, 17, 22]
输出:5

题目解析:

核心条件

  • 假设分数为 A[i]A[i],小于等于该分数的学生数量为 L[i]L[i],比该分数高的学生数量为 H[i]H[i]
  • 总学生数为 NN,则有: H[i]H[i]=NNL[i]L[i]
  • L[i]L[i]>H[i]H[i],即 2L[i]2L[i]>NN时,该学生会说谎。

思路分析:

  1. 成绩频率统计

    • 统计每个成绩出现的频率,构建一个频率表freq
  2. 排序并计算前缀和

    • 对成绩进行排序,并依次计算小于等于当前成绩的学生数量(即前缀和)。
  3. 判断是否说谎

    • 对于每个成绩,检查 2*prefix_sum > N 是否成立。
    • 如果成立,则该成绩对应的所有学生都算说谎。
  4. 累计结果

    • 将满足条件的学生数量累加,得到最终结果。

解决方案:

代码实现:

def solution(A):
    # 手动统计频率
    freq = {}
    for score in A:
        if score in freq:
            freq[score] += 1
        else:
            freq[score] = 1

    # 按成绩排序,计算前缀和
    sorted_scores = sorted(freq.keys())
    prefix_sum = 0  # 小于等于当前成绩的学生数量
    liars = 0  # 说谎的学生数量

    for score in sorted_scores:
        prefix_sum += freq[score]  # 累加当前成绩的学生数量
        if 2 * prefix_sum > len(A):
            liars += freq[score]  # 当前成绩的所有学生都算说谎
    
    return liars

代码解释:

  1. 统计频率

    • 构建成绩频率表 freq,统计每个成绩的出现次数。
    • 输入 A=[100,100,100]时,结果为 freq={100:3}
  2. 排序与前缀和

    • 将成绩按从低到高排序。
    • 依次计算小于等于当前成绩的学生数量(前缀和)。
  3. 判断是否说谎

    • 对于每个成绩,检查前缀和是否满足 2*prefix_sum > N
    • 如果满足,当前成绩对应的所有学生都说谎。
  4. 结果返回

    • 累计满足条件的学生数量。

示例测试:

  1. 样例1

    print(solution([100, 100, 100])) # 输出 3
    
  2. 样例2

    print(solution([2, 1, 3]))# 输出 2
    

时间复杂度:

时间复杂度

  1. 频率统计:遍历数组 A,时间复杂度为 O(N)O(N)

  2. 成绩排序:对 freq.keys() 进行排序,时间复杂度为 O(KlogK)O(Klog⁡K),其中 KK是不同分数的个数。

  3. 前缀和计算:遍历所有成绩,时间复杂度为 O(K)O(K)

  4. 总复杂度O(N+KlogK)O(N+KlogK)

空间复杂度:

  • 频率表:需要存储成绩频率,空间复杂度为 O(K)O(K)

  • 总空间复杂度O(K)O(K)

总结

通过频率统计和前缀和计算,能够高效判断每个分数下是否会说谎。
该算法的时间复杂度适中,适用于处理中等规模的成绩数据。