【剑指offer】最小的k个数

最小的K个数

题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

分析:要求的的最小的k个数,那么我们可以采用最大堆

先往最大堆里面存储k个数,然后剩下的数和堆顶元素比较,小于堆顶元素则替换堆顶元素,最后堆中剩下的k个数就是符合要求的最小的k个数

时间复杂度:O(N*log K)

type MaxHead []int

// 上浮
func (maxHead *MaxHead) up(index int){
	// 父节点
	parent:=index/2
	if index%2==0{
		parent-=1
	}
	// 存在孩子节点大于父节点的情况,对孩子节点进行上浮
	for index>0 && (*maxHead)[index]>(*maxHead)[parent]{
		(*maxHead)[index],(*maxHead)[parent]=(*maxHead)[parent],(*maxHead)[index] // 交换二者值

		// 继续往上
		index=parent
		parent=index/2

		if index%2==0{
			parent-=1
		}
	}
}

func (maxHead *MaxHead) push(x int){
	// 塞入底部,然后进行上浮操作
	*maxHead=append(*maxHead,x)
	maxHead.up(len(*maxHead)-1)
}

// 下沉
func (maxHead *MaxHead) down(index int) {
	// 左右孩子
	left:=index*2+1
	right:=index*2+2

	maxIndex:=index
	size:=len(*maxHead)

	// 寻找大于index节点的左右孩子
	if left<size && (*maxHead)[index]<(*maxHead)[left]{
		maxIndex=left
	}
	if right<size && (*maxHead)[index]<(*maxHead)[right]{
		maxIndex=right
	}

	// 交换元素,并进行下沉操作
	if maxIndex!=index{
		(*maxHead)[index],(*maxHead)[maxIndex]=(*maxHead)[maxIndex],(*maxHead)[index]
		maxHead.down(index)
	}else {
		//index的左右孩子都不大于index,那么对index的左右孩子继续进行下沉操作
		if left<size{
			maxHead.down(left)
		}
		if right<size{
			maxHead.down(right)
		}
	}
}

func (maxHead *MaxHead) pop() int{
	if len(*maxHead)==0{
		return -1
	}
	// 和尾部元素互换,然后下沉
	value:=(*maxHead)[0]
	size:=len(*maxHead)
	(*maxHead)[0],(*maxHead)[size-1]=(*maxHead)[size-1],(*maxHead)[0]

	// 移除尾部元素
	*maxHead=(*maxHead)[0:size-1]

	maxHead.down(0)

	return value
}

func getLeastNumbers(nums []int, k int) []int {
	if k==0{
		return nil
	}

	maxHead:=MaxHead{}

	for i:=0;i<len(nums);i++{
		if i<k{
			maxHead.push(nums[i])
		}else {
			if maxHead[0]>nums[i]{
				_=maxHead.pop()
				maxHead.push(nums[i])
			}
		}
	}

	var result []int
	for len(maxHead)!=0{
		result=append(result,maxHead.pop())
	}
	return result
}

posted @ 2019-09-23 16:16  西*风  阅读(143)  评论(0编辑  收藏  举报