染色法求解“微信群覆盖”,没收获你锤我!

题目:求微信群覆盖

微信有很多群,现进行如下抽象:

(1) 每个微信群由一个唯一的gid标识;

(2) 微信群内每个用户由一个唯一的uid标识;

(3) 一个用户可以加入多个群;

(4) 群可以抽象成一个由不重复uid组成的集合,例如:

g1{u1, u2, u3}

g2{u1, u4, u5}

可以看到,用户u1加入了g1与g2两个群。

画外音,注意:

gid和uid都是uint64;

集合内没有重复元素;

假设微信有M个群(M为亿级别),每个群内平均有N个用户(N为十级别).

现在要进行如下操作:

(1)  如果两个微信群中有相同的用户则将两个微信群合并,并生成一个新微信群;

例如,上面的g1和g2就会合并成新的群:

g3{u1, u2, u3, u4, u5};

画外音:集合g1中包含u1,集合g2中包含u1,合并后的微信群g3也只包含一个u1。

(2) 不断的进行上述操作,直到剩下所有的微信群都不含相同的用户为止

将上述操作称:求群的覆盖。

设计算法,求群的覆盖,并说明算法时间与空间复杂度。

画外音:58同城2013年校招笔试题。

前文《暴力法求解“微信群覆盖”》,通过以下四个步骤,实施了求解:

(1) 先初始化M个集合,用集合来表示微信群gid与用户uid的关系;

(2) 找到哪两个集合需要合并

(3) 对有重复元素的集合,进行集合合并

(4) 迭代步骤二和步骤三,遍历所有集合对,有相同元素的持续合并,直到算法结束;

但总的来说,暴力法效率非常低,暴力法求解“微信群覆盖”》同时提出了几个优化方向,今天重点讨论第一个优化方向:能不能一次合并多个集合?

暴力法中,判断两个集合set<i>和set<j>是否需要合并,思路是:遍历set<i>中的所有element,看在set<j>中是否存在,如果存在,说明存在交集,则需要合并。

哪些集合能够一次性合并?

当某些集合中包含同一个元素时,可以一次性合并。

怎么一次性发现,哪些集合包含同一个元素,并合并去重呢?

回顾一下工作中的类似需求:

M个文件,每个文件包含N个用户名,或者N个手机号,如何合并去重?

最常见的玩法是:

cat file_1 file_2 … file_M | sort | uniq > result

这里的思路是什么?

(1) 把M*N个用户名/手机号输出;

(2) sort排序,排序之后相同的元素会相邻

(3) uniq去重,相邻元素如果相同只保留一个;

排序之后相同的元素会相邻”,就是一次性找出所有可合并集合的关键,这是染色法的核心。

举一个栗子

假设有6个微信群,每个微信群有若干个用户:

s1={1,0,5} s2={3,1} s3={2,9}

s4={4,6} s5={4,7} s6={1,8}

假设使用树形set来表示集合。

d7b4cf96be386f24e6d6b08f3f79440193bd1c13

首先,给同一个集合中的所有元素染上相同的颜色,表示来自同一个集合。

f848eab2f9b17efdaf11d64099382801c2cc6592

然后,对所有的元素进行排序,会发现:

 ●  相同的元素一定相邻,并且一定来自不同的集合
 ●  同一个颜色的元素被打散了

 ff354f1737d8445db5f7a12c236d316d5af43d1b

这些相邻且相同的元素,来自哪一个集合,这些集合就是需要合并的,如上图:

 ●  粉色的1来自集合s1,紫色的1来自集合s2,黄色的1来自集合s6,所以s1s2s6需要合并
 ●  蓝色的4来自集合s4,青色的4来自集合s5,所以s4s5需要合并

不用像暴力法遍历所有的集合对,而是一个排序动作,就能找到所有需要合并的集合。

画外音:暴力法一次处理2个集合,染色法一次可以合并N个集合。

6fef2bb04bcfeaeecd7a5634ffe6ef6b7f778a05

集合合并的过程,可以想象为,相同相邻元素所在集合,染成第一个元素的颜色:

 ●  紫色和黄色,染成粉色
 ●  青色,染成蓝色

最终,剩余三种颜色,也就是三个集合:

s1={0,1,3,5,8}

s3={2,9}

s4={4,6,7}

神奇不神奇!!!

染色法有意思么?但仍有两个遗留问题

(1) 粉色1,紫色1,黄色1,三个元素如何找到这三个元素所在的集合s1s2s6呢?

(2) s1s2s6三个集合如何快速合并

画外音:假设总元素个数n=M*N,如果使用树形set,合并的复杂度为O(n*lg(n)),即O(M*N*lg(M*N))。

或许有朋友会问,怎么来排序?

拜托,面试别再问我基数排序了!

拜托,面试别再问我计数排序了!

拜托,面试别再问我桶排序了!

之前介绍了三种,时间复杂度是线性的排序算法。本例中,基数排序桶排序都是非常不错的选择。

还是那句话,思路比结论更重要,进一步的优化,且听下回分解。


原文发布时间为:2018-11-14

本文作者:  58沈剑

本文来自云栖社区合作伙伴“架构师之路”,了解相关信息可以关注“架构师之路”。

优秀的个人博客,低调大师

微信关注我们

原文链接:https://yq.aliyun.com/articles/669789

转载内容版权归作者及来源网站所有!

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

相关文章

发表评论

资源下载

更多资源
优质分享Android(本站安卓app)

优质分享Android(本站安卓app)

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS

Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是目前世界上流行的关系数据库管理系统,系统可移植性好、使用方便、功能强,适用于各类大、中、小、微机环境。它是一种高效率、可靠性好的、适应高吞吐量的数据库方案。

Apache Tomcat7、8、9(Java Web服务器)

Apache Tomcat7、8、9(Java Web服务器)

Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun 和其他一些公司及个人共同开发而成。因为Tomcat 技术先进、性能稳定,而且免费,因而深受Java 爱好者的喜爱并得到了部分软件开发商的认可,成为目前比较流行的Web 应用服务器。

Eclipse(集成开发环境)

Eclipse(集成开发环境)

Eclipse 是一个开放源代码的、基于Java的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。幸运的是,Eclipse 附带了一个标准的插件集,包括Java开发工具(Java Development Kit,JDK)。