leetcode - 1984. 学生分数的最小差值

416 阅读3分钟

「这是我参与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项的区间
  • 如何快速获取第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)的方法直接获取,而不是还需要进行一次排序呢?

期待有更好的解法。。。

image.png