一天一大 leet(最小区间)难度:困难-Day20200801

时间:2022-07-25
本文章向大家介绍一天一大 leet(最小区间)难度:困难-Day20200801,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

题目:

你有 k 个升序排列的整数数组。找到一个最小区间,使得 k 个列表中的每个列表至少有一个数包含在其中。

我们定义如果 b-a < d-c 或者在 b-a == d-c 时 a < c,则区间 [a,b] 比 [c,d] 小。

示例:

输入:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]]
输出: [20,24]
解释:
列表 1:[4, 10, 15, 24, 26],24 在区间 [20,24] 中。
列表 2:[0, 9, 12, 20],20 在区间 [20,24] 中。
列表 3:[5, 18, 22, 30],22 在区间 [20,24] 中。

注意:

  1. 给定的列表可能包含重复元素,所以在这里升序表示 >= 。
  2. 1 <= k <= 3500
  3. -105 <= 元素的值 <= 105

抛砖引玉

img

思路

刚看本题确实没有什么思路,看了官方的题解先去完成了最小覆盖子串:

more-011: 最小覆盖子串 (难度:困难)

再回看思路就比较明显了:

  • 把nums矩阵合并成一个有序数组,且记录每一个元素来源的行数
  • 最终求覆盖所有行数的数字区间

逻辑

  • 即要记录value又要记录行数,数组(二维){index:行数,value:值}
  • 新排序数组dp
  • left,right新数组指针
  • map记录待匹配的行索引即每行数量
  • Rleft,Rright终止区间
/**
 * @param {number[][]} nums
 * @return {number[]}
 */
var smallestRange = function(nums) {
  let dp = [],
      map = new Map(),
      left = 0,
      right = 0,
      Rleft = -Number.MAX_VALUE, // 结果区间的left索引
      Rright = -1, // 结果区间的right索引
      type = 0;  // 区间中数字来源的行数种类

  // 生成二维映射数组dp  行映射map
  for (let i = 0; i < nums.length; i++) {
      map.set(i, 0);
      for (let j = 0; j < nums[i].length; j++) {
          dp.push({ index: i, value: nums[i][j] })
      }
  }
  // dp排序
  dp.sort((a, b) => a.value - b.value);
  // 右边界
  while (right < dp.length) {
      let Rindex = dp[right].index, // 指针所在的数字来源行
          Rvalue = dp[right].value,  // 指针所在的数字
          RMvalue = map.get(Rindex)  // 区间内改行数字数量
      // 区间新增 来源于新行 则行类型+1 
      if (RMvalue === 0) ++type

      // 记录对应新增数字个数
      map.set(Rindex, ++RMvalue)

      // 来源行包含所有行即等于map-size
      while (type === map.size && left <= right) {

          let Lindex = dp[left].index,
              Lvalue = dp[left].value,
              LMvalue = map.get(Lindex);

  // 如果新的区间比较小则使用新区间
          if (Rvalue - Lvalue < Rright - Rleft) {
              Rleft = Lvalue
              Rright = Rvalue
          }
          // 丢弃一个数字,map记录减一
          map.set(Lindex, --LMvalue)
  // 丢失数字的计算为0,则说明该来源行在区间中无数字,减少行计数
          if (LMvalue === 0) --type
          // 做区间向右移动
          left++
      }
      // 右区间向右移动
      right++
  }
  return [Rleft, Rright]
};