Ý tưởng đầu tiên là phân 3 phần và tìm trong mỗi phần, cách này khá giống quick sort
def kth(a,k):
if k==1:
return min(a)
n=len(a)
pivot=a[random.randint(0,n-1)]
less=filter(lambda x:x<pivot,a)
nEq=a.count(pivot)
greater=filter(lambda x:x>pivot,a)
nL=len(less)
nG=len(greater)
if k<=nL:
return kth(less,k)
elif k<=nL+nEq:
return pivot
return kth(greater,k-nL-nEq)
Để cải tiến thuật toán ta phải tìm cách cho pivot chia đôi được mảng , ý tương tự thuật toán median of median
2/5n<indexof(pivot)<4/5n
Sau khi cải tiến
def median5(a): #find median size<=5
n=len(a)
return sorted(a)[n//2]
def kth(a,k):
if k==1:
return min(a)
n=len(a)
median=[]
i=0
while i<n//5:
median.append(median5(a[i*5:i*5+5]))
i+=1
if n%5:
median.append(median5(a[i*5:]))
if len(median)==1:
pivot=a[0]
else:
pivot=kth(median,len(median)//2)
less=filter(lambda x:x<pivot,a)
nEq=a.count(pivot)
greater=filter(lambda x:x>pivot,a)
nL=len(less)
nG=len(greater)
if k<=nL:
return kth(less,k)
elif k<=nL+nEq:
return pivot
return kth(greater,k-nL-nEq)
Độ phức tạp của thuật toán O(n).
chạy thử trên http://ideone.com/HAaIwg
chứng minh O(n)
http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-046j-design-and-analysis-of-algorithms-spring-2015/lecture-notes/MIT6_046JS15_writtenlec2.pdf