题目描述#
给定一个无重复元素的有序整数数组 nums,需要返回恰好覆盖数组全部数字的最小有序区间范围列表。
如果某个区间只有一个数字,就输出 "a";如果某个区间从 a 连续到 b,就输出 "a->b"。
知识边界#
分组循环#
这题适合用分组循环来做。因为数组已经有序,而且没有重复元素,所以只要相邻两个数满足 nums[j+1] == nums[j] + 1,它们就属于同一组。
遍历时先固定一组的起点 i,再让 j 一直向右扩展,找到这一组的结尾。这样 [i, j] 就对应一个完整的连续区间。
如果 i == j,说明这一组只有一个数字,直接转成字符串加入答案;如果 i != j,说明这一组是一段连续区间,就按 "左端点->右端点" 的格式加入答案。处理完这一组后,把 i 跳到 j + 1,继续找下一组。
这种写法的核心就是:不要一边扫描一边零散处理,而是先把满足同一性质的一整段找完整,再统一处理这一段。这里这一段的性质,就是“相邻元素连续加一”。
思路#
因为 nums 本身已经升序排列,所以每个区间一定对应数组中的一段连续下标。我们从左到右扫描数组,每次找到当前连续段的右边界,再根据这一段长度决定输出单个数字还是区间字符串。
整个过程中,每个元素最多进入一次某个分组,时间复杂度是 O(n)。除结果数组外,只用了少量指针变量,因此额外空间复杂度是 O(1)。如果输入是空数组,循环不会进入,最终直接返回空结果。
代码#
import "strconv"
func summaryRanges(nums []int) []string {
ans := []string{}
n := len(nums)
for i := 0; i < n; {
j := i
// 找这一组的结尾
for j < n-1 && nums[j+1] == nums[j]+1 {
j++
}
// 处理这一组 [i, j]
if i == j {
ans = append(ans, strconv.Itoa(nums[i]))
} else {
ans = append(ans, strconv.Itoa(nums[i])+"->"+strconv.Itoa(nums[j]))
}
// 进入下一组
i = j + 1
}
return ans
}