Find发帖水王
传说贴吧有一大“水王”,他不但喜欢发帖,还会回复其他ID发的每个帖子。坊间风闻该“水王”发帖数目超过了帖子总数的一半。如果你有一个当前论坛上所有帖子(包括回帖)的列表,其中帖子作者的ID也在表中,你能快速找出这个传说中的贴吧水王吗?
先来思考一下
这个问题的意思就是从一个有很多ID的列表中找到一个数目超过总数一半的ID。也就是数组中有一个数字出现的次数超过了数组长度的一半,找出这个数字。
最明显的思路是遍历一遍,记下每个数出现的次数。可是对于一个无序的数组你会拙计的,时间复杂度是O(n^2),空间复杂度是O(n)。如果你知道数组中最大的数是K,那可以利用array[k]++,两次遍历就可以求出来啦,时间复杂度是O(n),空间复杂度也是O(n),当然这方法是需要有条件的。
无序?
那就给他排序啊,用快排排好序,再一次遍历就可以了(只需要以一个MaxTimes和WateringId就可以解决了,自己想一下)。时间复杂度T(n)=O(nlgn)+O(n)=O(nlgn),空间复杂度是O(1)。其实压根就不需要再遍历,因为大于总数一半的ID肯定出现在N/2处,直接求得即可。时间复杂度也是T(n)=O(nlgn),没什么本质的变化。
可不可以不排序呢
当然可以,我们可以用Hash表,一次遍历处理,一次遍历求的ID。
时间复杂度是O(n),空间复杂度也是O(n)。时间复杂度减少了,空间复杂度没变化。
可以减少空间复杂度吗
ID的数量和一半有关系?这可以用分治策略来解决,把大问题化为若干子问题来解决。我们这样想,水王的ID比所有人的ID数目都多,如果我们删除一个水王的ID和一个其他人的ID,那最后剩余的ID就是水王的ID。当然我们不知道水王的ID是什么,可是只要我们删除的是不同的ID,那最后可能会剩很多ID,那就是水王的ID。基于这种思想,我们可以申请一个变长数组,首先放入第一个,然后从第二个ID开始判断是否和前一个相等,如果相等,那就删除已经存入的那个,否则加入。动态划分内存。时间复杂度是O(n),空间复杂度最好是O(1),最差同样是O(n)。。
其实呢,没必要非申请动态数组,这其实是一种思想。我们想象这是删除,可是我们并不删除,用一个变量来处理删除的事情,假设删除而已。用times记录ID的次数,用WateringId来记录水王的ID。当我们遍历的时候,如果此时数组中的ID和已经保存的水王ID一样,那times++,否则times--,如果times=0,我们需要保存此时的ID,并把times重新设为1。不同的相消,相同的累积而已。也就是说第一次times=0时记下当前ID作为水王的ID-,继续遍历,如果times=3则表示相等的ID有3个了,需要3个不同的ID才能使times变为0,times=0之后要记录新的ID作为水王哥的ID。遍历一遍足够找到水王的ID。
举个例子0,1,2,1,1,1
i=0,times=0   →    WateringId=0,times=1;
i=1,a[1]=1 != WateringId  →   times-- (times=0);
i=2,times=0  →    WateringId=1,times=1;
i=3,a[3]=2!= WateringId    →   times-- (times=0);
i=4,times=0  →   WateringId=1, times++ (times=1);
i=5,a[5]=1=WateringId  → times++  (times=2);
此时WateringId = 1,YES,Done!
不过不要忘了水王哥只是一个传说,不一定存在。所以最后要遍历一次,看看得出的水王ID的数量是不是大于N/2,是不是真的水王。
编码实现
  int FindWateringId(int Id[],int M)
  {
   int WateringId;
   int times=0;
   if(0==M) //还要判断输入数目是否有效
   return false;
   for(int i=0;i<M;i++)
   {
   if(times==0)
   {
   WateringId=Id[i];
   times=1;
   }
   else
   {
   if(WateringId==Id[i])
   times++;
   else
   times--;
   }
   }
   times=0;
   for(i=0;i<M;i++) //用来检测是否真的存在times>N/2的id
   {
   if(Id[i]==WateringId)
   times++;
   }
   if(times*2<=M) //ID数量大于N/2的水王不存在
   IsExisted=0;
   else
   IsExisted=1;
   return WateringId;
  
  }
时间复杂度只是O(n),空间复杂度只是O(1)而已。很nice的算法。
可是如果水王发的帖子数目刚好等于帖子总数的一半,那你还可以用上述方法解决吗?肯定行的通,换汤不换药而已,只要略加转变就可以完美解决。排序+统计可以,Hash也可以,删除的思想还行的通吗?对半?那删除完了不是把WateringId给弄没了吗?恩,也不一定啊。
如果水王的帖子数是总数的一半,那么总数必然是偶数,剩余的最后两个ID肯定有一个是水王的,不是全部,是其中一个!只需要最后加以判断即可。只需要稍微添加一些代码。
 int FindWateringId(int Id[],int M)
  {
   int WateringId;
   int times=0;
   if(0==M) //还要判断输入数目是否有效
   return false;
   for(int i=0;i<M;i++)
   {
   if(times==0)
   {
   WateringId=Id[i];
   times=1;
   }
   else
   {
   if(WateringId==Id[i])
   times++;
   else
   times--;
   }
   }
   times=0;
   int WateringId2=Id[M-1]; //假设最后一个是水王,总数目是偶数
   for(i=0;i<M;i++)
   {
   if(Id[i]==WateringId)
   times++;
   }
   if(times<M/2)
   WateringId=WateringId2; //这才是真的水王
  
   times=0;
   for(i=0;i<M;i++) //用来检测是否真的存在times>N/2的id
   {
   if(Id[i]==WateringId)
   times++;
   }
   if(times*2<M) //ID数量大于N/2的水王不存在
   IsExisted=0;
   else
   IsExisted=1;
   return WateringID;
  }
此版本同样适用于大于N/2的水王。
当然还有一种办法是用两个水王变量来解决这个问题。真假水王,最后谁的帖子多,谁就是真的水王,当然数目还要是满足times>=N/2的。这个也当然可以编码实现。
  int FindWateringId(int Id[],int M)
  {
   int WateringId;
   int FWateringId;
   int times=0;
   int Ftimes=0;
   if(0==M) //还要判断输入数目是否有效
   return false;
   for(int i=0;i<M;i++)
   {
   if(times==0)
   {
   WateringId=Id[i];
   times=1;
   }
   else if(Ftimes==0&&WateringId!=Id[i])
   { //不能让WateringId和FWateringId相等
   FWateringId=Id[i];
   Ftimes=1;
   }
   else
   {
   if(WateringId==Id[i])
   {
   times++;
   }
   else if(FWateringId==Id[i])
   {
   Ftimes++;
   }
   else //同时减去,这下子 直接少了3个。
   {
   times--;
   Ftimes--;
   }
   }
   }
   if(Ftimes>times)
   WateringId=FWateringId; //这才是真水王
   times=0;
   for(i=0;i<M;i++) //用来检测是否真的存在times>N的id
   {
   if(Id[i]==WateringId)
   times++;
   }
   if(times*2<M) //ID数量大于N/2的水王不存在
   IsExisted=0;
   else
   IsExisted=1;
   return WateringId;
  
  }
突然某一天,水王哥不见了,出现了3个发帖量超过总数1/4的水哥,你还能快速的找到他们吗?排序+统计完全可以搞定,无非是多了几个变量而已。类似a个发帖量超过总数1/b的问题都可以这么解决,这就好像一道ACM题了。有时间可以编码试试。
OK,水王问题解决!

Find发帖水王哥的更多相关文章

  1. 编程练习:寻找发帖"水王"扩展问题一

    回顾 寻找发帖水王的问题总结起来就是在一个数组中某一个元素出现次数超过了数组长度的一半,那么可以很顺利的找到这个元素,实现见"编程练习:寻找发帖水王" 扩展 上面的问题中,强调了某 ...

  2. 编程练习:寻找发帖"水王"

    题目: 寻找发帖"水王" 来源: 编程之美 分析 衍生:就是给定一个数组,其中某个元素出现次数超过了数组长度的一半,找出这个元素 方法s 方法1 对这个串进行遍历,同时对出现的元素 ...

  3. 编程练习:寻找发帖"水王"扩展问题二

    回顾 在前面两篇文章已经实现了水王id出现次数超过一半,以及水王id出现次数刚好一半 分析 借助上面水王id出现次数刚好出现一半的分析,其实这里就是找出数组中出现次数前三的元素,具体的分析,见前面两篇 ...

  4. Github Coding Developer Book For LiuGuiLinAndroid

    Github Coding Developer Book For LiuGuiLinAndroid 收集了这么多开源的PDF,也许会帮到一些人,现在里面的书籍还不是很多,我也在一点点的上传,才上传不到 ...

  5. Java for LeetCode 229 Majority Element II

    Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorit ...

  6. Java for LeetCode 169 Majority Element

    Given an array of size n, find the majority element. The majority element is the element that appear ...

  7. Majority Element || leetcode

    编程之美上一样的题目.寻找发帖水王. 利用分治的思想. int majorityElement(int* nums, int numsSize) { int candidate; int nTimes ...

  8. (medium)LeetCode 229.Majority Element II

    Given an integer array of size n, find all elements that appear more than ⌊ n/3 ⌋ times. The algorit ...

  9. 查找出现次数大于n/k的重复元素

    本文是对一篇英文论文的总结:Finding Repeated Elements.想看原文,请Google之. 这个问题的简单形式是“查找出现次数大于n/2的重复元素”.我们先从简单问题开始,然后再做扩 ...

随机推荐

  1. PHP利器-WAMPServer

    为了配置memcacheAdmin,牵涉到搭建PHP的环境,使用的是WAMPServer,安装之后,需要对apache进行配置, 端口,需要将wamp\bin\apache\Apache2.2.21\ ...

  2. iOS 改变UILabel部分颜色

    //协议 UILabel *xieLabel = [[UILabel alloc] init]; xieLabel.textColor = TextGrayColor; xieLabel.font = ...

  3. 第 15 章 组合模式【Composite Pattern】

    以下内容出自:<<24种设计模式介绍与6大设计原则>> 大家在上学的时候应该都学过“数据结构”这门课程吧,还记得其中有一节叫“二叉树”吧,我们上 学那会儿这一章节是必考内容,左 ...

  4. JNI/NDK开发指南(开山篇)

    转载请注明出处:http://blog.csdn.net/xyang81/article/details/41759643 相信很多做过Java或Android开发的朋友经常会接触到JNI方面的技术, ...

  5. jquery多级手风琴插件–accordion.js

    手风琴菜单一般用于下拉导航,由于外观非常简洁,使用起来跟手风琴一样可以拉伸和收缩而得名,项目中适当应用手风琴效果会给用户带来非常好的体验.本文借助jQuery插件轻松打造一个非常不错的手风琴效果的菜单 ...

  6. ANDROID_MARS学习笔记_S03_005_Geocoder、AsyncTask

    一.代码1.xml(1)AndroidManifest.xml <uses-permission android:name="android.permission.ACCESS_FIN ...

  7. *string++优先级的问题

    这个东西困扰了我几天,关于优先级问题确实是个恼人的东西,为了这个专门翻了C语言课本,得知 所有一目运算符都是第二级优先级 结合性是从右到左 那么*string++应该就是*(string++),也就是 ...

  8. 【CF】86 B. Petr#

    误以为是求满足条件的substring总数(解法是KMP分别以Sbeg和Send作为模式串求解满足条件的position,然后O(n^2)或者O(nlgn)求解).后来发现是求set(all vali ...

  9. 《IT运维之道》

    本书共分为5篇,机遇篇.做事篇.处事篇.技能篇和高级篇,从不同的层面阐述了IT运维人员 应掌握的方法及相关知识与技能.本书作者深入浅出.化繁为简,将信息化服务中晦涩的IT标准规范.流程体系用浅显易懂的 ...

  10. java基于xml配置的通用excel单表数据导入组件(一、实际应用过程)

    主要应用技术:poi + betwixt + reflect 一.实际应用过程 1.创建与目标表结构一样,表名为‘{目标表名}_import’的临时表: 2.创建用于存储导入问题数据的表:t_impo ...