题目如下:
You have
k
lists of sorted integers in ascending order. Find the smallest range that includes at least one number from each of thek
lists.We define the range [a,b] is smaller than range [c,d] if
b-a < d-c
ora < c
ifb-a == d-c
.Example 1:
Input:[[4,10,15,24,26], [0,9,12,20], [5,18,22,30]] Output: [20,24] Explanation: List 1: [4, 10, 15, 24,26], 24 is in range [20,24]. List 2: [0, 9, 12, 20], 20 is in range [20,24]. List 3: [5, 18, 22, 30], 22 is in range [20,24].
Note:
- The given list may contain duplicates, so ascending order means >= here.
- 1 <=
k
<= 3500- -105 <=
value of elements
<= 105.- For Java users, please note that the input type has been changed to List
>. And after you reset the code template, you'll see this point。
题目大意为有K个已排序好的数组,找到一个数对[a,b]使得每个数组中至少有一个元素在这个数对范围内,且要求[a,b]的范围最小。
以上述例子为例,这里找到了最终的范围是[20,24],但是实际上这里是找到了这样一个数组,[20,22,24],转化一下就是从每个数组里挑出一个数形成一个新的有序数组,保证这个数组的最小值与最大值的差值最小。
那么这里其实就比较容易想到思路了,从每个给定的数组里面挑最小元素形成一个新的数组A,将数组A排序后,得到最小值与最大值并计算他们的差值,然后找到数组A的最小值,将这个最小值所在的原数组的下一个元素更新到数组A中,再次排序,计算最小值最大值及差值并更新最终的结果。
结束条件:当需要更新数据A的最小值时,最小值已经是原数组的最后一个元素了,即可得到最终结果,注意结果更新条件。
另外:这里其实可以使用堆排序来简单实现,我这里直接用了GO标准库里面的sort。
源码如下:
type MyListNode struct {
itemValue int // 元素值
itemIdx int // 元素值在原数组的下标,方便找到下一个元素
lstIdx int // 记录此数组在nums中的下标
}
type SortLsts []MyListNode // 方便排序进行定义
func (sortLst SortLsts) Len() int {
return len(sortLst)
}
func (sortLst SortLsts) Less(i, j int) bool {
return sortLst[i].itemValue < sortLst[j].itemValue
}
func (sortLst SortLsts) Swap(i, j int) {
sortLst[i], sortLst[j] = sortLst[j], sortLst[i]
}
func smallestRange(nums [][]int) []int {
sortLst := []MyListNode{}
// 将每个数组的首元素加入到新数组中并排序
for idx := 0; idx < len(nums); idx++ {
sortLst = append(sortLst, MyListNode{nums[idx][0], 0, idx})
}
sort.Sort(SortLsts(sortLst))
minValue := sortLst[0].itemValue
maxValue := sortLst[len(nums)-1].itemValue
minRange := maxValue - minValue
for {
minIdx := sortLst[0].itemIdx
minIdx++
if minIdx >= len(nums[sortLst[0].lstIdx]) { // 已是最后一个元素,结束
break
}
// 下一个元素与当前值相等,不用做无谓计算
if nums[sortLst[0].lstIdx][minIdx] == sortLst[0].itemValue {
sortLst[0].itemIdx++
continue
}
// 最小值更新为下一个元素
sortLst[0].itemIdx++
sortLst[0].itemValue = nums[sortLst[0].lstIdx][minIdx]
sort.Sort(SortLsts(sortLst))
curRange := sortLst[len(nums)-1].itemValue - sortLst[0].itemValue
if curRange < minRange {
minRange = curRange
minValue = sortLst[0].itemValue
maxValue = sortLst[len(nums)-1].itemValue
}
}
return []int{minValue, maxValue}
}
细心的同学会发现,上面的实现中每次将新数组都进行了排序,其实并没有必要,只需要知道最大值与最小值就可以了,这里采用小顶堆来实现,提交后发现执行速度会快很多,代码如下:
type MyListNode struct {
itemValue int // 元素值
itemIdx int // 元素值在原数组的下标,方便找到下一个元素
lstIdx int // 记录此数组在nums中的下标
}
type HeapList []MyListNode // 实现堆
func (heapList HeapList) Len() int {
return len(heapList)
}
func (heapList HeapList) Swap(i, j int) {
heapList[i], heapList[j] = heapList[j], heapList[i]
}
func (heapList HeapList) Less(i, j int) bool {
return heapList[i].itemValue < heapList[j].itemValue
}
func (heapList *HeapList) Push(x interface{}) {
*heapList = append(*heapList, x.(MyListNode))
}
func (heapList *HeapList) Pop() (x interface{}) {
size := len(*heapList)
x = (*heapList)[size-1]
*heapList = (*heapList)[:size-1]
return x
}
func (heapList HeapList) Top() (x interface{}) {
return heapList[0]
}
func smallestRange2(nums [][]int) []int {
heapList := &HeapList{}
maxValue := nums[0][0]
for idx := 0; idx < len(nums); idx++ {
if maxValue < nums[idx][0] {
maxValue = nums[idx][0]
}
heap.Push(heapList, MyListNode{nums[idx][0], 0, idx})
}
heap.Init(heapList)
curItem := heapList.Top().(MyListNode)
minValue := curItem.itemValue
minRange := maxValue - minValue
startValue := minValue
endValue := maxValue
for {
topItem := heap.Pop(heapList).(MyListNode)
minIdx := topItem.itemIdx
minIdx++
if minIdx >= len(nums[topItem.lstIdx]) {
break
}
if maxValue < nums[topItem.lstIdx][minIdx] {
maxValue = nums[topItem.lstIdx][minIdx]
}
newItem := MyListNode{nums[topItem.lstIdx][minIdx], minIdx, topItem.lstIdx}
heap.Push(heapList, newItem)
curItem = heapList.Top().(MyListNode)
minValue = curItem.itemValue
curRange := maxValue - minValue
if minRange > curRange {
minRange = curRange
startValue = minValue
endValue = maxValue
}
}
return []int{startValue, endValue}
}