LeetCode 632. Smallest Range解题思路

题目如下:

You have k lists of sorted integers in ascending order. Find the smallest range that includes at least one number from each of the k lists.

We define the range [a,b] is smaller than range [c,d] if b-a < d-c or a < c if b-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:

  1. The given list may contain duplicates, so ascending order means >= here.
  2. 1 <= k <= 3500
  3. -105 <= value of elements <= 105.
  4. 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}
}

 

 

你可能感兴趣的:(LeetCode 632. Smallest Range解题思路)