Go语言实现快速选择

偶尔间看到一个问题:从海量数字中找到第k大的数

脑子里蹦出来的第一个念头是堆,复杂度O(nlogk)。后来想想好像在某些情况下可以用快速选择的思想,能达到O(n)。

快速选择的思想很简单,在快速排序的基础上实现,比如选择数字p为比较值,将一组数分为两半,我们将数字p的索引i与k比较就能知道第k个数字是在索引i的左边还是右边,还是恰好是i直接返回,接着只对包含k的那一边继续做相同过程就可以了。下面是go代码实现。

Tab:    其中加入了输出过程,来观察每一步的结果。

package main

import (
	"fmt"
	"math/rand"
)

func main() {
	org := rand.Perm(10)
	value := 7
	fmt.Println("原始切片: ", org)
	fmt.Printf(" 第%d个值: %d\n", value, findKthLargest(org, 0, len(org)-1, value))
	fmt.Println("最终切片: ", org)
}

func findKthLargest(s []int, start, end, k int) int {
	p := s[end]
	l := start
	for i := start; i < end; i++ {
		if s[i] <= p {
			fmt.Println("    交换:  i-", i, " l-", l, " p-", p)
			s[l], s[i] = s[i], s[l]
			l++
		}
		fmt.Println("  过程中: ", s)
	}
	s[l], s[end] = s[end], s[l]
	fmt.Println("一轮结束: ", s)
	fmt.Println("-------")

	if l == k {
		return s[l]
	} else if l < k {
		return findKthLargest(s, l+1, end, k)
	} else {
		return findKthLargest(s, start, l-1, k)
	}
}

但是用快速选择有限制,数字中不能包含相同的数字,否则会陷入循环。当然有重复数字的情况也可以用别的方式解决。

 

记录每天解决的一点小问题,积累起来就能解决大问题。 

猜你喜欢

转载自blog.csdn.net/Lazyboy_/article/details/88257161
今日推荐