求一個無序數組的中位數。
如:{2,5,4,9,3,6,8,7,1}的中位數爲5,{2,5,4,9,3,6,8,7,1,0}的中位數爲4和5。
要求:不能使用排序,時間複雜度儘可低。
實現思路:
解法一:快排思想
【背景知識】
1.快速排序可以實現將數據劃分爲 三部分 : 左邊小於基準值 基準值 右邊大於基準值位置
2.每次劃分都可以將基準值的最終確定, 那這樣的話,我們找中位數就很方便了。
如果劃分返回的區間
- 小於mid 去 右區間進行下一步查找
- 大於mid 去 左區間進行下一步查找
- ==mid 返回
代碼實現:
int PartionMid(int array[], int left ,int right)
{
int key = array[right];
int begin = left;
int end = right;
while (begin < end)
{
while (begin < end&&array[begin] <=key) //注意是<=
{
begin++;
}
while (begin < end&&array[end] >=key)
{
end--;
}
if (begin < end)
{
swap(array[begin],array[end]);
}
}
swap(array[begin], array[right]);
return begin;
}
//實現思路: 如果下標<mid去左區間找 ,如果下標>mid 去右區間找
int FindMid(int array[], int size)
{
int mid = (size-1)/ 2;
int left = 0;
int right = size - 1;
int index = 0;
index = PartionMid(array, left, right);
while (index != mid)
{
if (index < mid) //去右區間找
{
index = PartionMid(array, index+1, right);
}
else if (index>mid)//去左區間找
{
index = PartionMid(array, left, index-1);
}
}
return array[mid];
}
解法二: TopK問題
求中間大元素:建小堆,每次和當前堆最小值進行比較,
1.如果小於堆頂(當前堆最小值),說明不是 前K個數據,直接過濾掉
2.如果大於堆頂(當前堆最小值),說明有可能是 前K個數據
替換掉堆頂,再次對當前堆頂進行調整,滿足最小堆性質
另外:優先級隊列的底層也是通過建堆來實現的。默認是建大堆,此時就要編寫一個使其建小堆的仿函數了,其實也就是相當於修改了它的優先級。
代碼實現:
//優先級隊列實現 :天然的堆
int GetMidByQue(int arr[], int size)
{
int mid = (size) / 2+1;
struct Com
{
bool operator ()(int num1, int num2)
{
return num1 > num2;
}
};
priority_queue<int, vector<int>,Com> q;
for (int i = 0; i < mid; i++)
{
q.push(arr[i]);
}
for (int i = mid; i < size; i++)
{
if (arr[i]>q.top()) //替換掉元素
{
q.pop();
q.push(arr[i]);
}
}
//返回堆頂元素即可
if (!q.empty())
{
return q.top();
}
else
{
return -111111;
}
}