给定的输入是一个数组 A,其中每个元素代表一个学生的成绩。问题要求我们确定每个学生是否会说谎。具体地,我们需要判断,对于每个学生,其成绩小于或等于自己的学生数量是否大于比自己成绩高的学生数量。更简单地说,如果一个学生的成绩排在前半部分(即成绩小于或等于自己的人更多),那么他会说谎。
为了计算每个学生成绩小于等于自己的数量以及比自己高的学生数量,可以利用排序来简化问题。通过将学生成绩排序后,我们就能更容易地计算出每个学生的排名以及相对的学生分布。
解决方案设计
-
排序:
我们首先对成绩数组A进行排序。这是因为排好序的成绩可以帮助我们快速找出每个学生成绩小于或等于自己的学生数量。例如,排好序后,学生的成绩就按从小到大的顺序排列,我们可以利用这个信息直接计算成绩的相对位置。 -
计算每个学生的相对位置:
排序后的数组帮助我们确定每个学生在全班中的排名。对于一个给定的成绩,如果该成绩出现在数组中的索引位置i,那么该学生的成绩小于或等于自己的学生数量就是i + 1(因为索引是从 0 开始的,所以学生的成绩小于等于自己的学生数量是索引值加 1)。同时,比自己成绩高的学生数量可以通过N - (i + 1)来计算,其中N是学生总数。 -
判断是否说谎:
对于每个学生,我们需要判断:如果其成绩小于等于自己的学生数量大于比自己成绩高的学生数量,则该学生会说谎。可以通过比较这两个数量来做出判断。 -
实现步骤:
- 对成绩数组进行排序。
- 遍历每个学生,根据排序后的位置计算其成绩小于等于自己的学生数量和比自己高的学生数量。
- 进行条件判断,统计说谎的学生数量。
代码实现
javascript
复制代码
function countLyingStudents(A) {
const N = A.length;
const sortedA = [...A].sort((a, b) => a - b); // 对成绩进行升序排序
let lyingCount = 0;
// 遍历每个学生
for (let i = 0; i < N; i++) {
const score = A[i];
const lessThanEqualCount = sortedA.indexOf(score) + 1; // 小于等于该学生成绩的人数
const greaterThanCount = N - lessThanEqualCount; // 比该学生成绩高的人数
if (lessThanEqualCount > greaterThanCount) {
lyingCount++;
}
}
return lyingCount;
}
// 测试样例
console.log(countLyingStudents([100, 100, 100])); // 输出 3
console.log(countLyingStudents([2, 1, 3])); // 输出 2
console.log(countLyingStudents([30, 1, 30, 30])); // 输出 3
console.log(countLyingStudents([19, 27, 73, 55, 88])); // 输出 3
console.log(countLyingStudents([19, 27, 73, 55, 88, 88, 2, 17, 22])); // 输出 5
代码解析
- 排序:
sortedA = [...A].sort((a, b) => a - b);这一行将成绩数组A进行升序排序。由于 JavaScript 中sort()默认会将数组元素转为字符串比较,因此我们传入(a, b) => a - b来确保按数值排序。 - 计算成绩小于等于自己的学生数量:
sortedA.indexOf(score) + 1通过查找当前成绩在排序后的数组中的位置,得出该成绩小于等于自己的学生数量。由于indexOf返回的是 0-based 索引,因此我们加 1 得到学生数量。 - 计算比自己成绩高的学生数量:
greaterThanCount = N - lessThanEqualCount直接通过总学生数量减去小于等于当前成绩的学生数量,得到比当前成绩高的学生数量。 - 判断是否说谎:
如果lessThanEqualCount > greaterThanCount,即成绩小于等于自己的学生数量大于比自己高的学生数量,学生会说谎,我们就将lyingCount增加。
时间复杂度分析
- 排序的时间复杂度是
O(N log N),其中N是学生的数量。 - 遍历每个学生并计算其成绩小于等于自己的学生数量的时间复杂度是
O(N),因为每个学生的成绩只需要查找一次索引。
因此,整体的时间复杂度是 O(N log N),这是该问题的最优解。
总结
通过排序和计算每个学生的相对位置,我们能够高效地判断每个学生是否会说谎。这个方法避免了暴力求解的低效,且时间复杂度为 O(N log N),适用于大规模的数据处理。对于类似的排序问题,通常采用排序后再遍历的策略,不仅可以提高效率,还能简化问题的处理。