So I am given an (unsorted) array A of N distinct integers, I am trying to implement a divide-and-conquer algorithm to find the Kth smallest element (K ≤ N) in the array (i.e. it would be the overall smallest if K=1). The algorithm returns the value of the Kth smallest element in the array. I need it to run in O(N) time in the average case. Could anyone give me some hints?
-
possible duplicate of [How to find the kth largest element in an unsorted array of length n in O(n)?](http://stackoverflow.com/questions/251781/how-to-find-the-kth-largest-element-in-an-unsorted-array-of-length-n-in-on) – AShelly Jan 24 '12 at 20:24
7 Answers
Sephy, I'm going to walk this through very carefully. You always have to be careful when helping people with algorithms, because, and I cannot stress this enough, solving algorithm problems are to programmers what weight-lifting is to professional athletes. Knowing how to put yourself into the mode of thinking like a computer is what you will get paid to do in a few years. So if the solutions are just given to you, you're going to be the guy that bounces from job to job every 6 months instead of the guy who becomes the lead developer, or goes out on his own with a successful company.
Now that that rant is out of the way...
Traditionally, we think of algorithms that loop through the array once, and loop through it differently based on the first result, and repeat until we met some condition, to be O(n^2). Things that meet this criteria are selection sort, insertion sort, and bubble sort.
But it doesn't have to be. If we can properly divide the array into segments and prove the size of those segments, we can keep it on a low order.
And, with most divide and conquer algorithms, we can start in the middle.
Let A be an array of size N with N distinct elements in it.
Let M be the element that resides at A[N/2]
Let A-large be an array of all elements greater than M.
Let A-small be an array of all elements less than M.
What do we know about A-small and A large? Are they the same size? Maybe, but probably not.
Is size(A-small) > k
? or is it < k
?
If size(A-small) == k - 1
, wouldn't that make M the kth smallest element?
Is there something we can do to create a new value for k and do some recurrsion here?
I'm not going to finish this for you, because there should be plenty to chew on. These are the questions you need to ask yourself. @templatetypedef is 100% on the right track, this is just expanding on it.
If you have some more questions, ask them, but there should be enough here to allow you to solve it without robbing you of your mental exercise.

- 81,495
- 25
- 153
- 204
-
Thanks for the advice, @glowcoder. I was somewhat on the right track thanks to @templatetypedef but you made things a bit more clear for me. Also, I am very familiar with that rant haha, it's essentially my father's anthem. – Feb 16 '11 at 01:36
As a hint, think about how the quicksort partition step works. It splits the input up so that the pivot is in its final position, smallest elements are to the left, and larger elements are to the right. Given this information, and knowing what index you were trying to find, could you think of a way to recursively find the kth element?

- 362,284
- 104
- 897
- 1,065
-
4I may well be misunderstanding, but this doesn't seem like it would be O(n). With little (very little) thought on my end, it seems as if it would be O(n log n). – Mark Wilkins Feb 16 '11 at 00:38
-
I've tried implementing that but the only method I can come up with is if I sort the array first with quicksort then return the kth element, but my prof explicitly says to not do that. – Feb 16 '11 at 00:50
-
1@Mark Wilkins: I think templatetypedef is hinting at the quickselect algorithm, which is O(n) expected (but O(n²) worst-case). – Fred Foo Feb 16 '11 at 00:54
-
4@Mark Wilkins it is O(n) because, in opposite to QuickSort, you can throw aways the other half of the array after each iteration. Thus, you have n + n/2 + n/4 + n/8 + ... <= 2*n. +1, right answer. – Dave O. Feb 16 '11 at 01:00
-
@sephy7324 let me elaborate what templatetypedef means: After a split step in the quicksort algorithm you know how many elements are smaller then your pivot and how many are bigger. With this knowledge and your K, you can decide with which set to proceed. This is not sorting. – Dave O. Feb 16 '11 at 01:03
-
-
@Dave: The hoped for (and mostly expected) result is N + N/2 + N/4..., but the worst case is N + N-1 + N-2 + N-3 + N-4..., which is still N^2. – Jerry Coffin Feb 16 '11 at 02:11
-
import java.util.Scanner;
public class JavaApplication1 {
public static int findpivot(int a,int b,int c){
//System.out.println("x");
if(a > b){
if(c > a){
return a;
}
else if(c > b){
return c;
}
else{
return b;
}
}
else{
if(c > b){
return b;
}
else if(c > a){
return c;
}
else{
return a;
}
}
}
public static void find(int arr[],int l,int r,int target){
//System.out.println(1);
if(l >= r){
return;
}
int mid = (l+r)/2;
// System.out.println(1);
int pivot = findpivot(arr[mid],arr[l],arr[r]);
int i = l;
int j = r;
while(i<=j){
while(arr[i] < pivot)i++;
while(arr[j] > pivot)j--;
if(i<=j){
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;//
i++;
j--;
}
}
if(target <= (i-1)){
find(arr,0,i-1,target);
}
else{
find(arr,i,r,target);
}
}
public static void main(String args[]){
Scanner sc = new Scanner(System.in);
int t = sc.nextInt();
while(t-->0){
int n = sc.nextInt();
int arr[] = new int[n];
for(int i = 0;i<n;i++){
arr[i] = sc.nextInt();
}
int k = sc.nextInt();
find(arr,0,n-1,k-1);
System.out.println(arr[k-1]);
}
}
}
Time Complexcity is almost O(N).

- 804
- 8
- 9
Count the occurrences of each integer in the array in another array.

- 47,727
- 41
- 151
- 191
-
A good idea, but is of O(L) where L is the largest value. This means if L > 2*n, which you can't guarantee it isn't, then you lose your O(n) average. – corsiKa Feb 16 '11 at 00:46
-
@glowcoder: or if *L* = O(*n* lg lg *n*), or some other arbitrarily small step above O(n). – Fred Foo Feb 16 '11 at 00:49
For such classic problems, wikipedia works very well... See Selection algorithm on wikipedia

- 11,331
- 1
- 17
- 11
Here is my code. This is an O(n) solution. I didn't find anything good online, so I decided to post this here. Hope you find it helpful.
def Smallest(arr, k):
# # The brute force method
# if(len(arr)<k):
# return 0
# diff = []
# for i in range(len(arr)):
# for j in range(i+1, len(arr)):
# diff.append(abs(arr[i]-arr[j]))
# sortedDiff = sorted(diff)
# print(diff)
# print(sortedDiff)
# return sortedDiff[k-1]
#Efficient method
if(len(arr)<k):
return 0
# (i, j, minDiff, count) = (0, 1, arr[1]-arr[0], 0)
(i, j, minDiff) = (0, 1, [])
while(i < len(arr)):
if(j>len(arr)-1):
i+=1
if(i==len(arr)-1):
break
j=i+1
else:
minDiff.append(abs(arr[i]-arr[j]))
j+=1
# print(minDiff)
(minElement, count) = (minDiff[0], 0)
for i in range(len(minDiff)):
if(count<k):
minElement = minDiff[i]
count+=1
# print(minElement, count)
if(count==k):
return minElement
else:
continue
else:
# print("This part is being hit")
continue

- 1
- 1
- 1