題目:輸入n個數,找出其中最小的k個數。例如輸入4、5、1、6、2、7、3、8這8個數字,則最小的4個數字是1,2,3,4。
思路:這道題目是典型的top k問題。兩種方法:
(1)如果允許改變量列,半快速排序,是基準值正好為第k個數,那麼基準值左邊的都是小於它的,即可得到最小的k個數(求最大的過程類似),時間複雜度o(n)。
(2)不允許改變量列,採用維護陣列的方法,建立乙個最大堆。遍歷數列,如果數字小於堆頂,那麼堆頂很明顯不是最小的k個數,更新堆頂,直到所有數字都已經與堆頂比較,堆上的數字即為最小的k個數。
半快速排序在面試題29裡講過,在此不再討論。見連線:
堆的實現可以用陣列,也可以利用stl裡的multiset容器,下面是分別用兩種實現過程的求解**:
1.用multiset實現
typedef multiset> intset;
typedef multiset>::iterator setiterator;
void getleastnumbers(const vector& data, intset& leastnumbers, int k)}}
}
2.用陣列實現
如果陣列從0開始計數(也有從1開始),順序儲存堆的結點,那麼對於結點i,它的左右子結點和父親有這樣的關係:
左兒子:2*i+1
右兒子:2*i+2
父親: (i-1)/2
建堆過程:上濾建堆。因為陣列總是在末尾插入新的元素,這時候比較它和父親的大小,比父親小則交換,逐步上移,直到大於父結點。
插入過程:和建堆過程類似,上濾法。
維護二叉堆的過程是每次和堆頂元素比較,此時需要採取的是下濾過程,因此這裡需要上濾和下濾兩個例程。
void swap(int& a, int& b)
void siftup(int* a, int n)
void siftdown(int* a, int n)
}
topk演算法:
void topk(int *a, int n, int k)
} for(int i = 0; i < k; ++i)
cout << heap[i] << " ";
cout << endl;
delete heap;
}
劍指offer 面試題30 最小的k個數
題目描述 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4.題目分析 這道題最簡單的思路莫過於把n個整數排序,然後最前面的k個數就是最小的k個數,但是時間複雜度是o nlogn 我們應該想一想有沒有更快的方法。解法一 o n 的演...
劍指Offer 面試題30 最小的k個數
題目 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,思路 1 首先,使用快排中的思路 每進行一次快排,會確定乙個位置上的數字,使得該位置前的數字都小於該數字,而該位置後的數字都大於該數字。2 所以,要找最小的k個數,即某一次快...
《劍指offer》面試題30 最小的k 個數
劍指offer 面試題30 最小的k 個數 1.題目描述 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,2.解題思路 1。全排序。時間複雜度o nlogn 2。partiton思想 用快速排序,時間複雜度o n 3。最大堆 時...