一、问题描述
在小C的班级里,有N个学生,每个学生的成绩是A_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 的学生数量多于分数比他高的数量时,第 i 个学生会说谎。
数据结构选择
我们可以使用一个数组来存储学生的分数。为了快速统计分数 <= A_i 的学生数量和分数比 A_i 高的学生数量,我们可以使用以下方法:
- 排序:对分数数组进行排序,这样我们可以通过二分查找快速找到分数 <=
A_i的学生数量。 - 计数:使用一个计数数组来统计每个分数出现的次数,这样可以快速计算分数 <=
A_i的学生数量。
算法步骤
- 排序:对分数数组进行排序。
- 计数:遍历排序后的数组,统计每个分数出现的次数。
- 计算:对于每个学生,计算分数 <=
A_i的学生数量和分数比A_i高的学生数量,判断是否满足说谎条件。
伪代码
public static int solution(int[] A) {
// 1. 对分数数组进行排序
Arrays.sort(A);
// 2. 统计每个分数出现的次数
int[] count = new int[101]; // 因为分数范围是 0 到 100
for (int score : A) {
count[score]++;
}
// 3. 计算说谎的学生数量
int liarCount = 0;
for (int i = 0; i < A.length; i++) {
int score = A[i];
int lessOrEqualCount = 0;
// 计算分数 <= score 的学生数量
for (int j = 0; j <= score; j++) {
lessOrEqualCount += count[j];
}
// 计算分数比 score 高的学生数量
int greaterCount = A.length - lessOrEqualCount;
// 判断是否说谎
if (lessOrEqualCount > greaterCount) {
liarCount++;
}
}
return liarCount;
}
代码提示
根据上述思路,在 solution 方法中实现具体的代码逻辑。注意以下几点:
- 使用
Arrays.sort对分数数组进行排序。 - 使用一个计数数组
count来统计每个分数出现的次数。 - 遍历每个学生的分数,计算分数 <=
A_i的学生数量和分数比A_i高的学生数量,判断是否满足说谎条件。
三、知识总结:
-
数组排序:使用
Arrays.sort(A)对数组进行排序。这是一个很实用的操作,在很多算法中,对数据进行排序可以简化后续的处理逻辑。理解:排序后的数组能方便地进行范围统计等操作,比如这里通过排序可以更高效地计算小于等于某个值的元素个数。 -
数组元素计数:通过
count[score]++来统计每个分数出现的次数。这种方式可以快速获取每个值在数组中的频率,对于需要根据值的频率来做决策的算法很有用。 -
双层循环统计:内层循环用于计算小于等于当前分数的元素个数,外层循环遍历数组中的每个元素。这种双层循环的结构在处理涉及元素之间关系和统计的问题时经常出现。理解:需要注意内层循环的边界条件和计算逻辑,确保准确统计。
-
学习建议
-
理解数组操作:数组是编程中的基础数据结构,要深入理解数组的索引、遍历和修改等操作。比如这里的
count[score]++,要明白score作为索引的含义以及如何通过它来更新计数。 -
掌握循环逻辑:对于多层循环,要仔细分析每层循环的目的和控制条件。可以通过手动模拟代码执行过程来理解,比如拿一个简单的小数组,手动计算每一步的
lessOrEqualCount和greaterCount,这样能更好地理解代码的逻辑。 -
练习类似算法问题:找一些类似的统计数组中元素关系的问题来练习,比如计算数组中某个范围内元素的和、统计满足特定条件的元素对数量等,加深对这种类型算法的理解。
学习计划
-
制定刷题计划
- 确定目标和范围:如果是学习数据结构和算法相关内容,可以根据不同的主题(如排序、搜索、统计等)来划分刷题范围。例如,针对本题涉及的统计数组中元素关系的类型,可以集中刷一批类似的题目。可以从简单到复杂,先从基础的数组遍历和统计题目开始,再到像本题这样有一定逻辑复杂度的题目。
- 安排时间:每天安排固定的时间用于刷题,比如每天 1 - 2 小时。可以将时间分成两部分,一部分用于新题目的练习,另一部分用于复习和总结之前做过的题目。在使用 MarsCode AI 刷题时,可以根据它提供的难度分级和题目类型分类来合理安排每个阶段的刷题量。
工具运用
- 结合 AI 刷题与其他学习资源
- 代码调试工具:结合代码调试工具(如 Java 中的调试器)和 MarsCode AI。当代码出现问题时,在 MarsCode AI 中分析错误信息后,可以使用调试工具来逐步执行代码,查看变量的值和程序的执行流程,更深入地理解代码的问题所在,尤其是对于像本题这种有一定逻辑复杂度的代码。