#include #include #include int solution(std::vector A) { int N = A.size(); std::vector count(101, 0); // 统计每个分数的出现次数 std::vector prefix_sum(101, 0); // 前缀和数组 for (int score : A) { count[score]++; } for (int i = 1; i <= 100; ++i) { prefix_sum[i] = prefix_sum[i - 1] + count[i]; } int liar_count = 0; // 判断每个学生是否说谎 for (int score : A) { int less_or_equal = prefix_sum[score]; int greater = N - less_or_equal; if (less_or_equal > greater) { liar_count++; } } return liar_count; } int main() { // Add your test cases here std::cout << (solution({100, 100, 100}) == 3) << std::endl; std::cout << (solution({2, 1, 3}) == 2) << std::endl; std::cout << (solution({30, 1, 30, 30}) == 3) << std::endl; std::cout << (solution({19, 27, 73, 55, 88}) == 3) << std::endl; std::cout << (solution({19, 27, 73, 55, 88, 88, 2, 17, 22}) == 5) << std::endl; return 0; } 算法思路 这个算法的目的是确定在一个给定的分数数组中,有多少个学生可能在说谎。每个学生声称他们的分数在所有人的分数排名中,有一半或者少于一半的人分数比他们低。我们需要根据这个条件来判断每个学生是否在说谎。 统计每个分数的出现次数:使用一个大小为101的数组count来记录每个分数(从0到100)出现的次数。数组下标对应分数,数组值对应该分数的出现次数。 计算前缀和:使用另一个大小为101的数组prefix_sum来计算到当前分数为止,所有分数出现的总次数。即prefix_sum[i]表示从0到i(包括i)所有分数的总出现次数。 判断每个学生是否说谎:遍历每个分数,对于每个分数score,计算: less_or_equal:分数小于等于score的学生数量,这可以通过prefix_sum[score]得到。 greater:分数大于score的学生数量,这可以通过总人数N减去less_or_equal得到。 如果less_or_equal大于greater,说明声称“有一半或者少于一半的人分数比我低”的学生在说谎,因此增加说谎学生计数器liar_count。 返回结果:返回说谎学生的总数。 算法分析 时间复杂度 统计每个分数的出现次数:遍历一次数组A,时间复杂度为O(N)。 计算前缀和:遍历一次count数组,时间复杂度为O(100) = O(1)(常数时间,相对于N可以忽略)。 判断每个学生是否说谎:再次遍历一次数组A,时间复杂度为O(N)。 总的时间复杂度为O(N) + O(1) = O(N)。 空间复杂度 使用了两个大小为101的数组count和prefix_sum,因此空间复杂度为O(1)(相对于N,101是一个常数)。 还需要存储输入数组A,所以总的空间复杂度为O(N + 1) = O(N)。 优点 高效:算法的时间复杂度为O(N),适合处理大规模数据。 直观:通过统计分数出现次数和使用前缀和数组,可以直观地计算出每个学生是否满足条件。 缺点 空间利用:虽然空间复杂度为O(N)是可以接受的,但是额外的两个大小为101的数组对于非常小的N(例如N远小于101)来说可能有些浪费。然而,对于大多数实际应用场景,这不是一个严重的问题。 总结 这个算法通过统计分数出现次数和计算前缀和,高效地解决了判断学生是否说谎的问题。算法的时间复杂度为O(N),空间复杂度为O(N),适用于处理大规模数据。