[编程之美] PSet2.3 寻找发帖“水王”

问题描述:

Tango是微软亚洲研究院的一个试验项目。研究院的员工和实习生们都很喜欢在Tango上面交流灌水。传说,Tango有一大“水王”,他不但喜欢发贴,还会回复其他ID发的每个帖子。坊间风闻该“水王”发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的Tango水王吗?

解题思路:

思路一:

    书中第一种方法是先对ID进行排序,再遍历排序后的ID列表,统计每个ID出现的次数,如果有一个ID出现次数超过总数一半,从而寻找到最大次数的ID。对这个排好序的ID列表查找“水王”的ID并不需要扫描一遍所有序列找最大,或是找总数超过一半的ID,可以直接定位到第N/2项(下标从0开始)就可以了。O(NlogN)+O(1)

    需要对这么大的一个列表进行统计排序非常麻烦,有一种方式可以避免排序:

思路二:

    缩小问题规模,分而治之:每次删除两个不同的ID(不管是否包含“水王”的ID),那么在剩下的ID列表中,“水王”ID出现的次数必然仍然超过总数的一半。

    不断重复这个过程,把ID列表中ID的总数降低,转化为更小的问题。耗时O(N),只需常数的额外内存。

    代码如下:

//下面的代码是寻找发帖水王的代码
//输入:ID数组,用Type *ID表示。元素数据类型为Type,以及数组大小N
//输出:ID水王的ID号
//方法:交替的抵消两个相邻的不同ID号,如果相同ID则让标志位+1
Type findShuiWang(Type *ID , int N)
{
    Type candidate ;
    int nTimes = 0;//标志位
    for(int i=0 ; i<N ; i++){
        if(nTimes == 0){
            candidate = ID[i];
            nTimes++;
        }
        else{
            if(ID[i] == candidate){
                nTimes++;
            }
            else{
                nTimes--;
            }
        }
    }
    return candidate;
}


扩展问题:

随着Tango的发展,管理员发现,“超级水王”没有了。统计结果表明,有3个发帖很多的ID,他们的发帖数目都超过了帖子总数目N的1/4。你能从发帖ID列表中快速找出他们的ID吗?

这个扩展问题还是上题所述的对偶问题,由于这三个水王每个ID出现次数都超过1/4,所以非水王ID不到1/4,也就是水王ID:非水王ID > 3:1,因此可以设定三个标志位nTmes[3]进行统计,如果出现一个与当前三个候选者均不同的ID号,则让当前三个候选nTimes[i]--;最终nTimes[i]不为0的就是最终的三个水王。时间复杂度O(N)

typedef int Type;
void Find(Type* ID, int N ,Type candidate[3])
{
	const Type ID_NULL = -1;//定义一个不存在的ID
	int nTimes[3], i;
	nTimes[0]=nTimes[1]=nTimes[2]=0;
	candidate[0]=candidate[1]=candidate[2]=ID_NULL;
	for(i = 0; i < N; i++)
	{
		if(nTimes[0]==0)
		{
			nTimes[0]=1;
			candidate[0]=ID[i];
		}
		else if(nTimes[1]==0)
		{
			nTimes[1]=1;
			candidate[1]=ID[i];
		}
		else if(nTimes[2]==0)
		{
			nTimes[2]=1;
			candidate[2]=ID[i];
		}
		else if(ID[i]==candidate[0])
		{
			nTimes[0]++;
		}
		else if(ID[i]==candidate[1])
		{
			nTimes[1]++;
		}
		else if(ID[i]==candidate[2])
		{
			nTimes[2]++;
		}
		else
		{
			nTimes[0]--;
			nTimes[1]--;
			nTimes[2]--;
		}
	}
	return;
}

int main()
{
	Type ID[] = {0,4,1,4,0,4,1,4,1,0,3,3,0,3,3,3};
	Type candidate[3];

	Find(ID , 16 , candidate);
	for(int i=0 ; i<3 ; i++)
		cout << candidate[i]<<" ";
	cout<<endl;
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值