介绍一种解决选择问题的分治算法。randonmizedSelect算法以随机版快排为模型。与快排的区别为:

快排会递归处理划分的两边,而此算法只处理划分的一边。

快排期望运行时间为O(nlgn),此算法的期望运行时间为O(n)。这里假设输入数据都是互异的。

此算法返回数组A[p..r]中第i小的元素。

package main

import (
	"math/rand"
	"time"
)


func partition(arr []int, p, r int) int {
	x := arr[r]
	i := p-1
	for j := p; j < r; j++ {
		if arr[j] < x {
			i++
			arr[i], arr[j] = arr[j], arr[i]
		}
	}
	arr[i+1], arr[r] = arr[r], arr[i+1]
	return i+1
}


// 产生在min和max之间的随机数
func RandInt64(min, max int64) int64 {
	rand.Seed(time.Now().UnixNano())
	return min+rand.Int63n(max-min+1)
}

// 随机化的partition
func randomizedPartition(arr []int, p, r int)  int {
	i := int(RandInt64(int64(p), int64(r)))
	arr[r], arr[i] = arr[i], arr[r]
	res := partition(arr, p, r)
	return res
}

// 随机选择算法 
func randomizedSelect(arr []int, p, r, i int) int {
	if p == r {
		return arr[p]
	}
	q := randomizedPartition(arr, p, r)
	k := q-p+1

	if i == k {
		return arr[q]
	} else if i < k {
		return randomizedSelect(arr, p, q-1, i)
	} else {
		return randomizedSelect(arr, q+1, r ,i-k)
	}
}

func main() {
	var arr = []int{2,3,4,1,0,5,6,9,8,7}
	target := 4
	ans := randomizedSelect(arr,0,len(arr)-1,target)
	println(ans)
}