这是在课上提的两个很有意思的问题,用比较笨的方法都可以轻松予以解决,但优化就是一件很有意思的事情。
众数问题:
给定数组A[1…n],找出其中出现次数严格大于
半数以上的元素或者报告这样的众数不存在
注:各元素之间不能比大小,只能比较彼此是否相等。
普通解法略去,下面给出O(n)算法的大体思路:
设置一个节点node,里面有element和counter两部分,前者用来盛放元素值,counter是计数器。
具体操作步骤:对给定数组从头到尾进行扫描,首先将element赋值为A[1],counter赋值为1,
如果counter为零则element赋值为当前元素,counter加1;
扫描过程中如果元素与element相等则counter加1;
如果元素与element不相等且counter大于1,则counter减1;
如果元素与element不相等且counter等于1,则counter置0;
整个过程结束后,再对该节点中存放的元素从头到尾进行一遍扫描,判断是否为众数。
关键在于:假如存在众数的话,剩下的那一个元素一定是所求众数,假如留下的元素不是众数,则该数组中一定没有众数。
由于前后只进行了两次扫描,所以复杂度为O(n)。
社会名流问题:
给定一个n×n邻接矩阵,确定是否存在一个i,
其满足在第i列所有项(除了第ii项)都为1,并
且第i行所有项(除了第ii项)都为0。
插话:这个其实就是有向图求源与汇的变形,O(n)算法非常经典,也是先找出一个来,如果有源肯定是该元素,该元素如果不是源,则就没有社会名流了
大致的算法思路:
随便取一个非对角线元素,比如Array[i][j],如果Array[i][j]=0成立,则j不是社会名流,于是删去第j行和第j列。
同样,如果Array[i][j]=1成立,则删去第i行和第i列;
总之,无论对应项取何值,都可以删去一行和一列,因此整个操作只耗费O(n)的时间。
重复此操作直至剩下最后一个元素。
最后,检验该元素是否为社会名流即可。
如果该元素不是,则该群人中不存在社会名流。
大体就是这样吧,可能有些地方说的不太清楚,不过确实感觉挺好玩的~