来源:编程之美2.3
题目:该"水王"发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的Tango水王吗?
问题实质:寻找数组中出现的半数以上的数.
思路:如果每次删除两个不同的id,则剩下的水王id依然超过总数的一半,可以不断重复这个过程。
问题扩展:如果有3个id,发贴总数都超过了帖子总数的四个之一,如果快速找到他们。思路都差不多。
/*题目:该"水王"发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,
其中帖子作者的ID也在表中,你能快速找出这个传说中的Tango水王吗?
问题实质:寻找数组中出现的半数以上的数.
拓展:有3个数,他们的出现次数都超过了总数的1/4.
*/
public class ShuiWang2_3 {
/**
* @param args
*/
public static void main(String[] args) {
int[] id = { 1, 1, 1, 5, 1, 1, 1, 3, 1, 7, 1, 3, 1, 2, 1, 1, 4, 56, 1, 12, 4, 1, 3, 4,
1, 1, 1, 3, 1, 1, 1, 5, 1, 1, 3, 12, 1, 2, 1, 2, 2, 2, 2, 2,2 };
System.out.println(MoreHalfNum(id,id.length));
int id2[] = {5, 5, 5, 7, 7, 8, 8, 8, 8, 2,
2, 2, 2, 2, 2, 2, 2, 5, 5, 5,
6, 5, 6, 7, 7, 7, 7, 7, 7, 7,
7, 5, 7, 2, 2, 2, 5, 5, 5, 8};
printArr(findMore(id2));
}
//每次从数组中删除两个不同的数,不断重复这个过程
//算法中当然不是真的删除数,而是用一个计数器巧妙的实现“删除”
public static int MoreHalfNum(int data[],int n)
{
int candidate=0;//候选值
int nTime=0;//候选值出现的次数
for(int i=0;i<n;i++){
if(nTime==0)//nTime为0时说明需要重新立候选值
{
candidate=data[i];
nTime++;
}else{
if(data[i]==candidate)nTime++;//又出现了,权值加1
else nTime--;//不等,权值减1
}
}
return candidate;
}
public static int[] findMore(int[] data){
int[] res=new int[3];//数组,存出现次数最多的三个数
int[] nTimes={0,0,0};//数组,存每个候选值出现的次数
int i;
for(i=0;i<data.length;i++){
int index;
//1.如果存在某个index,使得nTimes[index]==0,则重新赋候选值
for(index=0;index<3;index++){
if(nTimes[index]==0){
res[index]=data[i];
nTimes[index]++;
break;
}
}
if(index<3)continue;
//2.如果存在index,满足res[index]=id[i]),则对应权值加1
for(index=0;index<3;index++){
if(res[index]==data[i]){
nTimes[index]++;
break;
}
}
if(index<3)continue;
//3.其它情况,对应权值都减1
for(index=0;index<3;index++){
nTimes[index]--;
}
}
return res;
}
private static void printArr(int[] a){
for(int s:a){
System.out.print(s+" ");
}
}
}