1.数组中出现次数超过一半的数字
思路一:数组中出现次数超过一半的数字是排好序后数组的中位数,我们采用随机快速排序的思路,先在数组中随机选择一个数字,然后调整数组中数字的顺序,使得比选中数字小的数字都在他的左面,大的都在他的右面。如果选中数字的下标刚好是2/n,这个数就是中位数,如果小于,则中位数位于其右面,如果大于,中位数位于其左面。可以继续进行递归查找。
注:要注意无效操作的情况(数组为空,长度小于1),以及数组中本来就没有出现次数超过一半的数字。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int len=numbers.size();
if(len<=0) return 0;
int mid=len>>1;
int start=0;
int end=len-1;
int index=Partition(numbers,len,start,end);
while(index!=mid)
{
if(index>mid)
{
end=index-1;
index=Partition(numbers,len,start,end);//中位数在左面
}
else
{
start=index+1;
index=Partition(numbers,len,start,end);//中位数在右面
}
}
int result=numbers[index];
int times=0;
for(int i=0;i<len;i++)
{
if(numbers[i]==result)
times++;//判断出现次数是否超过一半
}
return times*2>len?result:0;
}
int Partition(vector<int> &numbers,int length,int start,int end)//快排核心函数
{
if(length<=0||start<0||end>=length)
return false;
int index=RandomInRange(start,end);
Swap(&numbers[index],&numbers[end]);//随机生成一个点,与尾结点互换
int small=start-1;
for(index=start;index<end;index++)
{
if(numbers[index]<numbers[end])
{
++small;
if(small!=index)
Swap(&numbers[index],&numbers[small]);//说明small与index直接有大于end下标的数字
}
}
++small;
Swap(&numbers[small],&numbers[end]);
return small;
}
int RandomInRange(int start,int end)
{
srand (time(NULL));
return rand() % (end-start+1) + start;//随机数函数
}
void Swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
}
};思路二:遍历数组时保存两个值,一个是数组中的一个数字,一个是次数,如果下一个数字与此数字相同,那么次数加一,如果不相同,次数减一。如果次数为0,那么保存下一个数字,重置次数为1.由于要找的数字出现的次数比其他所有数字出现的次数之和还要多,因此最后一个次数被设为1的数字就是要找的数字。
class Solution {
public:
int MoreThanHalfNum_Solution(vector<int> numbers) {
int len=numbers.size();
if(len<=0) return 0;
int result=numbers[0];//当前数
int count=1;//次数
for(int i=1;i<len;i++)
{
if(numbers[i]!=result)
{
count--;//不等于,次数--
}
else
{
count++;//等于,次数++
}
if(count==0)
{
result=numbers[i];
count=1;//次数为0,重置
}
}
int times=0;
for(int i=0;i<len;i++)
{
if(numbers[i]==result)
times++;
}
return times*2>len?result:0; //加一个判断
}
};2.最小的k个数
思路一:仍基于快排,如果基于数组的第k个数字来调整,则使得比第k个数字小的所有数字都位于数组的左边,比k个数字大的所有数字都位于数组的右边,这样调整之后,位于数组左中左边的k个数字就是最小的k个数字。
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> res;
int len=input.size();
if(len<=0||k<=0||k>len) return res;
int start=0;
int end=len-1;
int index=Partition(input,len,start,end);
while(index!=k-1)
{
if(index>k-1)
{
end=index-1;
index=Partition(input,len,start,end);
}
else
{
start=index+1;
index=Partition(input,len,start,end);
}
}//直到index为k时,此时前k个数就是最小的k个数
for(int i=0;i<k;i++)
res.push_back(input[i]);
return res;
}
int Partition(vector<int> &numbers,int length,int start,int end)//快排核心函数
{
if(length<=0||start<0||end>=length)
return false;
int index=RandomInRange(start,end);
Swap(&numbers[index],&numbers[end]);//随机生成一个点,与尾结点互换
int small=start-1;
for(index=start;index<end;index++)
{
if(numbers[index]<numbers[end])
{
++small;
if(small!=index)
Swap(&numbers[index],&numbers[small]);//说明small与index直接有大于end下标的数字
}
}
++small;
Swap(&numbers[small],&numbers[end]);
return small;
}
int RandomInRange(int start,int end)
{
srand (time(NULL));
return rand() % (end-start+1) + start;//随机数函数
}
void Swap(int *a,int *b)
{
int temp=*a;
*a=*b;
*b=temp;
}
};思路二:用于处理海量数据,利用最大堆(根节点的值总是大于它的子树中任意节点的值)或者红黑树(STL里面的set和multiset)
class Solution {
public:
typedef multiset<int,greater<int>> intSet;
typedef multiset<int,greater<int>>::iterator setIterator;
void GetLeastNumbers_Solution(const vector<int> &input, int k,intSet& leastNumbers) {
leastNumbers.clear();
if(k<1||input.size()<k) return;
vector<int>::const_iterator iter=input.begin();
for(;iter!=input.end();iter++)
{
if(leastNumbers.size()<k)
{
leastNumbers.insert(*iter);//先插入k个数
}
else
{
setIterator iterGreatest=leastNumbers.begin();
if(*iter<*(leastNumbers.begin()))
{
leastNumbers.erase(iterGreatest);
leastNumbers.insert(*iter);//如果小于set里的最大值,就替换掉最大值
}
}
}
}
};3.数据流中的中位数
思路一:如题1,利用快速排序的partition函数寻找中位数。
思路二:最大堆和最小堆。
class Solution {
public:
vector<int> res;
void Insert(int num)
{
res.push_back(num);
}
double GetMedian()
{
sort(res.begin(),res.end());
int len=res.size();
if(len%2==1)
return (double)res[len/2];
else
return (double)((res[len/2]+res[len/2-1])/2.0);
}
};

京公网安备 11010502036488号