汇总区间(双指针)

139 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招打卡活动,点击查看活动详情

一、题目描述:

给定一个无重复元素的有序数组,返回恰好覆盖数组中所有数字的最小有序区间范围列表。

输入: [0,1,2,4,5,7]
输出: ["0->2","4->5","7"]

二、思路分析:

我们从数组的位置 0 出发,向右遍历。每次遇到相邻元素之间的差值大于 1 时,我们就找到了一个区间。遍历完数组之后,就能得到一系列的区间的列表。

这道题首先大家要注意的是:当数组不连续的情况发生在相邻index时,保存begin和end,否则保存begin即可。

function summaryRanges (nums) {
  let ans = []
  if (nums.length === 0) {
    return ans
  }
  let begin = nums[0]
  let end = nums[0]
  for (let i = 1; i < nums.length; i++) {
    if (nums[i] - nums[i - 1] === 1) {
      end = nums[i]
      continue
    }
    // 当数组不连续的情况发生在相邻index时
    if (begin !== end) {
      ans.push(begin + '->' + end)
    } else {
      ans.push(begin)
    }
    begin = nums[i]
    end = nums[i]
  }
  // 汇总最后一个区间
  if (begin !== end) {
    ans.push(begin + '->' + end)
  } else {
    ans.push(begin)
  }
  return ans
}

let arr = [0,1,2,4,5,7]
let res = summaryRanges(arr)
console.log(res)

我们在nums的末尾push一个2 ** 32,保证最后一次将所有区域全部计算,可以减少循环后的再次判断场景。

function summaryRanges (nums) {
  let ans = []
  if (nums.length === 0) {
    return ans
  }
  nums.push(2 ** 32)
  let begin = nums[0]
  let end = nums[0]
  for (let i = 1; i < nums.length; i++) {
    if (nums[i] - nums[i - 1] === 1) {
      end = nums[i]
      continue
    }
    if (begin !== end) {
      ans.push(begin + '->' + end)
    } else {
      ans.push(begin)
    }
    begin = nums[i]
    end = nums[i]
  }
  return ans
}

上面代码中begin表示区间的起点值,end表示区间的终点值。下面我们也可以通过索引标记区间的位置,是另一种实现方式。

function summaryRanges (nums) {
  let ret = []
  let i = 0
  let n = nums.length;
  while (i < n) {
    let low = i;
    i++
    while (i < n && nums[i] === nums[i - 1] + 1) {
      i++
    }
    let high = i - 1;
    let temp = ['' + nums[low]]
    // 每次遇到相邻元素之间的差值大于 1 时
    if (low < high) {
      temp.push('->')
      temp.push('' + nums[high])
    }
    ret.push(temp.join(''))
  }
  return ret
}

在遍历过程中,维护下标 low 和 high 分别记录区间的起点和终点,对于任何区间都有 low≤high。当得到一个区间时,根据 low 和 high 的值生成区间的字符串表示。

[nums[low], '->', nums[high]]
调用数组的join来拼接字符串

四、总结:

合并区间我们使用双指针即可完成区间统计。双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。