[ 数学知识 ]908. 最小差值 I

387 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第30天,点击查看活动详情

每日刷题 2022.04.30

题目

  • 给你一个整数数组 nums,和一个整数 k 。
  • 在一个操作中,您可以选择 0 <= i < nums.length 的任何索引 i 。将 nums[i] 改为 nums[i] + x ,其中 x 是一个范围为 [-k, k] 的整数。对于每个索引 i ,最多 只能 应用 一次 此操作。
  • nums 的 分数 是 nums 中最大和最小元素的差值。 
  • 在对  nums 中的每个索引最多应用一次上述操作后,返回 nums 的最低分数。

示例

  • 示例1
输入: nums = [1], k = 0
输出: 0
解释: 分数是 max(nums) - min(nums) = 1 - 1 = 0
  • 示例2
输入:nums = [0,10], k = 2
输出:6
解释:将 nums 改为 [2,8]。分数是 max(nums) - min(nums) = 8 - 2 = 6
  • 示例3
输入:nums = [1,3,6], k = 3
输出:0
解释:将 nums 改为 [4,4,4]。分数是 max(nums) - min(nums) = 4 - 4 = 0

提示

  • 1 <= nums.length <= 10^4
  • 0 <= nums[i] <= 10^4
  • 0 <= k <= 10^4

解题思路

  • 根据题意可知:nums的分数就是nums数组中的最大值和最小值的差值。需要使nums的最小分数即:最小差值。
  • 并且会给你一个范围K,对于nums数组中的每一位都可以进行一次操作,但是操作的范围必须在K内,即:[-K, K]
  • 那么我们首先考虑,之前做过求最小值的题目,是否需要每次都将最小值取出来,对其进行操作,再将其塞回优先队列中。# 6039. K 次增加后的最大乘积仔细考虑一下,并不适合本题,因为之前这道题并没有规定数组中的每个数只能操作一次,并且本题中每次操作的范围是K,并不是一个具体的数值。
  • 再考虑下,画个图,可以看到当nums数组中的最大值,记为max;最小值记为min。整个范围为2 * k
    • 当最大值和最小值的距离相差大于2 * K的时候, (数组中其他的元素都被包含在内)最大值和最小值的距离差值 - 2 * K就是最小差值
    • 当最大值和最小值的距离相差小于2 * K的时候,(数组中其他的元素都被包含在内)最小差值为0
  • 为什么要选择最大值和最小值为基准呢?因为最大值和最小值相当于是一个数组的上下界,如果能够使这两个元素之间的差值最小,那么数组中其他的元素也就可以达到,因为数组中其他元素是被包含在上下界之内的,所以完全可以在k范围内达到。

AC代码

var smallestRangeI = function(nums, k) {
  nums.sort((a, b) => {
    return b - a;
  });
  let cha = nums[0] - nums[nums.length - 1];
  return cha > 2 * k ? cha - 2 * k : 0;
};

总结

  • 贫富差距,富(相当于最大值),贫(相当于最小值),富人提供更多的工作机会,穷人应聘上岗,实现共同富裕。
  • 为什么只选择数组中的最大值和最小值讨论呢?因为当前最小值在K范围内,能够到达的位置,那么其上面的元素也都能到达,相当于形成了上下界。