「这是我参与2022首次更文挑战的第18天,活动详情查看:2022首次更文挑战」
力扣 1984. 学生分数的最小差值
题目描述
给你一个 下标从 0 开始 的整数数组 nums ,其中 nums[i] 表示第 i 名学生的分数。另给你一个整数 k 。
从数组中选出任意 k 名学生的分数,使这 k 个分数间 最高分 和 最低分 的 差值 达到 最小化 。
返回可能的 最小差值 。
示例 1:
- 输入:nums = [90], k = 1
- 输出:0
- 解释:选出 1 名学生的分数,仅有 1 种方法:
- [90] 最高分和最低分之间的差值是 90 - 90 = 0
- 可能的最小差值是 0
示例 2:
- 输入:nums = [9,4,1,7], k = 2
- 输出:2
- 解释:选出 2 名学生的分数,有 6 种方法:
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 4 = 5
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 1 = 8
- [9,4,1,7] 最高分和最低分之间的差值是 9 - 7 = 2
- [9,4,1,7] 最高分和最低分之间的差值是 4 - 1 = 3
- [9,4,1,7] 最高分和最低分之间的差值是 7 - 4 = 3
- [9,4,1,7] 最高分和最低分之间的差值是 7 - 1 = 6
- 可能的最小差值是 2
解题思路
根据题意,我们需要从数组中取出k位,并从中取到最高值和最低值;并且保证这来个差值最小化。
想法
- 假如我们将数据排序,因为是每个数之间的差距是最小的。、
- 因此,长度为K的数组之间的最大最小值之间的差值也是最小的,那么在这些差距最小的数组中,使用滑动窗口,将每个k长度数组都遍历一遍,就能找到所有K长度数组的最小值。
- 其实排序就是将 K 个不同数字组成的数组的最小组合方式找到。
- 滑窗就是最小中找最小。
问题:
- 如何取出
k位?- 这很简单,为了使k个数字极差最小,那就顺序取最接近的k个数字,
k位也就是数组的第i项 - 第i + k - 1项的区间
- 这很简单,为了使k个数字极差最小,那就顺序取最接近的k个数字,
- 如何快速获取第
i项 - 第i + k - 1项的区间的区间中的最大值和最小值呢?- 这也很简单,在我们使用参数 nums 时进行一次排序,升序降序都可以,最后只是代码的表现形式不一样
- 然后我们只需要获取 nums[i] 和 nums[i + k - 1] 即可获取最大值和最小值
初版
function minimumDifference(nums: number[], k: number): number {
// 最终返回的最小区间差值
let min = 0x7fffffff;
// 如果整数k为1,就不需要遍历了,直接返回 0 就好
if (k === 1) {
return 0
}
// 先排序
nums.sort((a,b) => {
return a - b
})
for (let i = 0; i < nums.length; i++) {
// 如果最小值是 0 的话 就直接跳出,肯定没有更小的了
if(!min) {
break
}
let j = i + k - 1;
// 如果当前我们获取区间的范围存在
if (j < nums.length) {
// 比较两个的值之间的差距
min = Math.min(min, nums[j] - nums[i])
} else {
// 如果超出了 当前的数组范围 就直接跳出循环,不需要进行比对了
break
}
}
return min
};
升级一下
function minimumDifference(nums: number[], k: number): number {
if (k === 1) {
return 0
}
// 先排序
nums.sort((a,b) => a - b)
if (k === 2) {
return nums[nums.length -1] - nums[nums.length -2]
}
let min = nums[k - 1] - nums[0];
for (let i = 0; i + k - 1 < nums.length; i++) {
let j = i + k - 1;
min = Math.min(min, nums[j] - nums[i]);
}
return min
};
思考
我这应该并不是最优解。。。能不能直接O(n)的方法直接获取,而不是还需要进行一次排序呢?
期待有更好的解法。。。