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来拼接字符串
四、总结:
合并区间我们使用双指针即可完成区间统计。双指针,指的是在遍历对象的过程中,不是普通的使用单个指针进行访问,而是使用两个相同方向(快慢指针)或者相反方向(对撞指针)的指针进行扫描,从而达到相应的目的。