無序數組中求最大值和最小值的最少比較次數
無序數組中求最大值和最小值的最少比較次數
原理介紹
求一個無序數組中的最大值和最小值是一個很常見的情況, 一般來說, 最大值和最小值不是同一個元素, 我們可以通過下面幾種方法來求:
- 排序算法:將數組排序后, 第一個元素是最小值,最后一個元素是最大值,以快排平均復雜度為例,時間復雜度 $O(NlogN)$,空間復雜度: $O(logN)$,比較次數: $NlogN$ ;
- 兩個元素記錄最大值和最小值,判斷每個值是否大於最大值或者最小值, 比較次數: $2*N$';
- 使用兩個值記錄最大值和最小值, 每次取出兩個值,先進行比較,小的與最小值比較,大的與最大值比較 , 比較次數: $1.5*N$
- 將相鄰的數進行比較,大的放在偶數位置,小的放在奇數位置, 最后奇數位置比較和偶數位置對應比較,得到最大值和最小值,比較次數: $1.5*N$ ;
- 分治法, topK 問題的簡化版本分成兩部分,找到前半部分的 Min Max, 最后比較結果可得到最后的值
方法3 和方法4的 過程很接近, 方法3 更為容易實現, 具體實現可見后續
算法實現
方法1 快排
// 找到數組元素的最大值和最小值
vector<int> findMinMax(vector<int> arr)
{
sort(arr.begin(),arr.end());
return {arr[0],arr.back()};
}
方法 2
// 找到數組元素的最大值和最小值
vector<int> findMinMax(vector<int> arr)
{
int min_ = INT_MAX,max_ = INT_MIN;
for(int i=0;i<arr.size();++i)
{
if(arr[i] > max_)
max_ = arr[i];
if(arr[i] < min_)
min_ = arr[i];
}
return {min_,max_};
}
方法 3
使用兩個值記錄最大值和最小值, 每次取出兩個值,先進行比較,小的與最小值比較,大的與最大值比較 , 比較次數: $1.5*N$
// 找到數組元素的最大值和最小值
vector<int> findMinMax(vector<int> arr) {
int min_ = INT_MAX,max_ = INT_MIN;
// 處理前面偶數個元素
for(int i=0;i<arr.size()/2;++i) {
// 得到兩個元素的最大值和最小值
int tmp_min,tmp_max;
if(arr[i] < arr[i+1]) {
tmp_min = arr[i];
tmp_max = arr[i+1];
} else {
tmp_min = arr[i+1];
tmp_max = arr[i];
}
// 比較,更新最大值和最小值
if(tmp_max > max_) max_ = tmp_max;
if(tmp_min < min_) min_ = tmp_min;
}
// 處理數組個數為奇數的情況 // 處理最后一個元素
if(arr.size()%2) {
int tmp = arr.back();
if(tmp > max_) max_ = tmp;
if(tmp < min_) min_ = tmp;
}
return {min_,max_};
}
方法 4
比較前面偶數個元素,小的放在奇數位置,大的放在偶數位置, 比較次數: $1.5*N$
// 找到數組元素的最大值和最小值
vector<int> findMinMax(vector<int> arr) {
int min_ = INT_MAX,max_ = INT_MIN;
// 調整位置, 小的位於奇數,大的位置偶數
for(int i=0;i<arr.size()/2;i++) {
if(arr[i] > arr[i+1]) swap(arr[i],arr[i+1]);
}
// 更新最大值和最小值
for(int i=0;i<arr.size()/2;i++) {
if(arr[i] < min_) min_ = arr[i];
if(arr[i+1] > max_) max_ = arr[i+1];
}
// 處理數組個數為奇數的情況 // 處理最后一個元素
if(arr.size()%2) {
int tmp = arr.back();
if(tmp > max_) max_ = tmp;
if(tmp < min_) min_ = tmp;
}
return {min_,max_};
}
方法5
在N個數中求最小值Min和Max, 分成兩個部分,依次取Min和Max,
略