作者 |  channingbreeze
责编 | 郭芮

小史是一个应届生,虽然学的是电子专业,但是自己业余时间看了很多互联网与编程方面的书,一心想进BAT互联网公司。

今天小史去了一家社交小巨头公司面试了。

面试现场

面试官:举个例子,比如现在有5个宠物,分别是小猫1,小猫2,小猫3,小狗1,小狗2。再告诉你小猫1和小狗1是好朋友,小猫2和小狗1是好朋友,小猫3和小狗2是好朋友。这样它们之间就形成了2个朋友圈。

小史:先对宠物们编号,然后一对好友关系就用一个bitmap来存。判断两个bitmap之间是否有交集,只需要进行与操作。而融合的话只需要进行并操作。

小史在纸上画了半天进行思考。一分钟过去了。

小史:我好像知道了,可以在遍历好友关系的同时,把他们进行合并,我用双向链表来做。初始时,每个宠物都是一个单独的节点,而一对好友关系过来的时候,先判断两个节点是否在同一个链表中,如果不在,就把两个节点所在的链表头尾相连,形成一个新链表。

一分钟过去了。


请教大神


回到学校,小史把面试情况和吕老师说了一下。

小史:这个我早就考虑到了,1和3是好朋友,并不是连接1和3,而是去找1的根和3的根,发现他们都是2,所以他们本来就在一个朋友圈,不需要相连。

并查集

小史:哦,对,堆也是一种树,但是它是二叉树,而且是完全二叉树,所以才能用数组存,并且用坐标的方式计算父亲孩子节点。

吕老师:今天的树同样可以用数组存,初始时刻数组中都是-1,当有两个节点需要合并时,只需要将其中一个数的根的值设为另一个数的根的下标就行。

小史在纸上划拉半天,终于有点明白了。

理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了。

UnionFindSet.java

/** * @author xiaoshi on 2018/11/4. */public class UnionFindSet {

    // 存储并查集    private int[] elements;

    UnionFindSet(int n) {        // 初始都为-1        elements = new int[n];        for (int i = 0; i < n; i++) {            elements[i] = -1;        }    }

    // 找到一个数的根    public int find(int x) {        while(elements[x] != -1) {            x = elements[x];        }        return x;    }

    // 把两个数的根连起来    public void union(int x, int y) {        // x的根        int rootx = find(x);        // y的根        int rooty = find(y);        // 如果不是同一个根就连起来        if(rootx != rooty) {            elements[rootx] = rooty;        }    }

    // 计算形成了多少颗树    public int count() {        int count = 0;        for(int i=0; i<elements.length; i++) {            if(elements[i] == -1) {                count++;            }        }        return count;    }

    // 打印并查集    public void print() {        for(int i=0; i<elements.length; i++) {            System.out.print(elements[i] + " ");        }        System.out.println();    }

}

Main.java

/** * @author xiaoshi on 2018/11/4. */public class Main {

    public static void main(String[] args) {

        UnionFindSet ufs = new UnionFindSet(10);

        ufs.union(0, 1);        ufs.union(0, 2);        ufs.union(3, 4);        ufs.union(3, 1);        ufs.union(5, 7);        ufs.union(7, 8);        ufs.union(7, 8);

        System.out.println(ufs.count());

    }

}

运行结果

4

基于树高度的合并优化

吕老师:1和2是好朋友,2和3是好朋友,3和4是好朋友,4和5是好朋友。

理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了。

UnionFindSetMergeOptimize.java

/** * @author xiaoshi on 2018/11/4. */public class UnionFindSetMergeOptimize {

    // 存储并查集    private int[] elements;    // 存储树的高度    private int[] heights;

    UnionFindSetMergeOptimize(int n) {        elements = new int[n];        heights = new int[n];        for (int i = 0; i < n; i++) {            // 初始都为-1            elements[i] = -1;            // 初始高度1            heights[i] = 1;        }    }

    // 找到一个数的根    public int find(int x) {        while(elements[x] != -1) {            x = elements[x];        }        return x;    }

    // 把两个数的根连起来    public void union(int x, int y) {        // x的根        int rootx = find(x);        // y的根        int rooty = find(y);        // 如果不是同一个根就连起来        if(rootx != rooty) {            // 矮树向高树合并            if(heights[rootx] > heights[rooty]) {                elements[rooty] = rootx;            } else if(heights[rootx] < heights[rooty]) {                elements[rootx] = rooty;            } else {                // 如果高度相同,随便合并                elements[rootx] = rooty;                // 但是记得合并后高度加一                heights[rooty]++;            }

        }    }

    // 计算形成了多少颗树    public int count() {        int count = 0;        for(int i=0; i<elements.length; i++) {            if(elements[i] == -1) {                count++;            }        }        return count;    }

    // 打印并查集    public void print() {        for(int i=0; i<elements.length; i++) {            System.out.print(elements[i] + " ");        }        System.out.println();        for(int i=0; i<heights.length; i++) {            System.out.print(heights[i] + " ");        }        System.out.println();    }

}

Main.java

/** * @author xiaoshi on 2018/11/4. */public class Main {

    public static void main(String[] args) {

        UnionFindSetMergeOptimize ufsmo = new UnionFindSetMergeOptimize(10);

        ufsmo.union(0, 1);        ufsmo.union(1, 2);        ufsmo.union(2, 3);        ufsmo.union(3, 4);        ufsmo.union(4, 5);        ufsmo.union(5, 6);        ufsmo.union(6, 7);        ufsmo.union(7, 8);        ufsmo.union(8, 9);

        System.out.println(ufsmo.count());

    }

}

运行结果

1

路径压缩优化

理解了算法之后,小史的代码写起来也是非常快,不一会儿就写好了。

UnionFindSetPathOptimize.java

/** * @author xiaoshi on 2018/11/4. */public class UnionFindSetPathOptimize {

    // 存储并查集    private int[] elements;

    UnionFindSetPathOptimize(int n) {        // 初始都为-1        elements = new int[n];        for (int i = 0; i < n; i++) {            elements[i] = -1;        }    }

    // 找到一个数的根    public int find(int x) {        // 保存原始x值        int originX = x;        // 找到根        while(elements[x] != -1) {            x = elements[x];        }        // 把这一路的节点全部直接连到根上        while(originX != x) {            int tempX = originX;            originX = elements[originX];            elements[tempX] = x;        }        return x;    }

    // 把两个数的根连起来    public void union(int x, int y) {        // x的根        int rootx = find(x);        // y的根        int rooty = find(y);        // 如果不是同一个根就连起来        if(rootx != rooty) {            elements[rootx] = rooty;        }    }

    // 计算形成了多少颗树    public int count() {        int count = 0;        for(int i=0; i<elements.length; i++) {            if(elements[i] == -1) {                count++;            }        }        return count;    }

    // 打印并查集    public void print() {        for(int i=0; i<elements.length; i++) {            System.out.print(elements[i] + " ");        }        System.out.println();    }

}

Main.java

/** * @author xiaoshi on 2018/11/4. */public class Main {

    public static void main(String[] args) {

        UnionFindSetPathOptimize ufspo = new UnionFindSetPathOptimize(10);

        ufspo.union(0, 1);        ufspo.union(1, 2);        ufspo.union(2, 3);        ufspo.union(3, 4);        ufspo.union(4, 5);        ufspo.union(5, 6);        ufspo.union(6, 7);        ufspo.union(7, 8);        ufspo.union(0, 9);

        System.out.println(ufspo.count());

    }

}

运行结果:

1

看着自己写的代码,小史还是忍不住赞叹。

作者:channingbreeze,国内某互联网公司全栈开发。

声明:本文为作者投稿,版权归对方所有。


 热 文 推 荐 

☞ 微博回应裁员;罗永浩股权被冻结;“隐形贫困”人群最爱苹果 | 极客头条

☞ 快看,我们的分布式缓存就是这样把注册中心搞崩塌的!

☞ Linux 常用命令如何使用?

特别策划 | 盘点区块链的2018:技术与工具演进篇

☞ 企业云存储建设之路

开除“野狗”式程序员,团队的效率提高了

AI in 美团:吃喝玩乐背后的黑科技

☞ 老程序员肺腑忠告:千万别一辈子靠技术生存!

print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"

喜欢就点击“好看”吧!

算到怀疑人生!如何用并查集解决朋友圈个数问题?相关推荐

  1. 并查集---找朋友圈个数问题,连通度问题,等的有效算法

    数据结构方面,你了解并查集么? 上交05年计算机复试 上机 畅通工程问题: 例题1 修路连通问题 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通 ...

  2. 并查集解决朋友圈问题

    引入 最近在网上看到了这样一道面试题: 假如已知有n个人和m对好友关系(存于数组r)如果两个人是直接或间接的好友(好友的好友的好友-),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋 ...

  3. 海贼OJ并查集练习题:朋友圈

    海贼OJ并查集练习题:朋友圈 题目描述 ​ 所谓一个朋友圈子,不一定其中的人都互相直接认识. ​ 例如:小张的朋友是小李,小李的朋友是小王,那么他们三个人属于一个朋友圈. ​现在给出一些人的朋友关系, ...

  4. 并查集c++代码_[Leetcode 每日精选](本周主题-并查集) 547. 朋友圈

    题目难度: 中等 原题链接 今天继续来做并查集的问题, 这道题仍然比较基础, 而且也是个比较接近现实的问题了. 大家在我的公众号"每日精选算法题"中的聊天框中回复 并查集 就能看到 ...

  5. java并查集找朋友圈_图—并查集(解决朋友圈问题)

    图也是一种 非线性结构,是由多个顶点组成的关系集合组成的一种数据结构.图可以分为两种,无向图和有向图. ★图的定义: ★典型问题: 利用图能够解决很多问题,这里有一个较为典型的问题,假如已知有n个人和 ...

  6. java并查集找朋友圈_并查集求朋友圈最大人数

    #include #include using namespace std ; int findRoot( int set[ ], int s ) { if (s == set[s]) return ...

  7. 并查集——小米笔试题求朋友圈个数,分小组个数

    先给出小米的题: 已知有n个人和m对好友关系(存于数组r).如果两个人是直接或间接的好友(好友的好友的好友-),则认为他们属于同一个朋友圈,请写程序求出这n个人里一共有多少个朋友圈. 假如:n = 5 ...

  8. 数据结构之并查集:并查集解决案例, Python——21

    并查集解决案例畅通工程 案例问题介绍: 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府"畅通工程"的目标是使全省任何两个城镇间都可以实现交通 ...

  9. hdu--1231--并查集连分量的个数

    我觉得 这题 是纯粹的 并查集 可以算成 入门题吧 问你有几章桌子 就是问你有几个 连通块嘛 一个道理 touch  me 这题 我采用了下 father[x]开始 初始化为-1 1 #include ...

最新文章

  1. 6 OC 中的isa 指针
  2. 【C++11】30分钟了解C++11新特性
  3. INFORMATICA 的部署实施之 BACKUPRESTORE
  4. java httpclient 进度条_如何使用Apache HttpClient 4获取文件上传的进度条?
  5. 华为把服务器虚拟底层锁了,华为全面关闭解码锁服务:马上升级到很吓人的技术!...
  6. 软件工程师必学的9件事
  7. 二维数组名作为实参或者形参
  8. django 指令  基于the django book
  9. Ubuntu18.04设置简单密码
  10. 《Axure RP 9实战指南》Axure RP 9.0最新版汉化问题
  11. 2018年烽火通信c语言笔试题,2018-9-19 烽火通信C++面经
  12. 衣带渐宽终不悔,为UI消得人憔悴
  13. 如何每天学习10小时,依然精力充沛?(超实用教程)
  14. MD5校验判断文件是否一样
  15. php三D立体模拟,【HTML5】3D模型--百行代码实现旋转立体魔方实例
  16. php大商创商城,news.php · Mihok/ecshop大商创商城 - Gitee.com
  17. 郭炜实用Python程序设计慕课:chapter13面向对象程序设计
  18. linux单点登录命令,配置RHEV中Linux 虚拟机使用 IPA(IDM)实现单点登录的方法
  19. layui的表单——自定义验证规则
  20. 【云原生 | 从零开始学Kubernetes】二十七、配置管理中心Secret和rbac授权

热门文章

  1. Python中装入包pandas和matplotlib
  2. 中国碳纤维增强热塑性(CFRTP)复合材料市场趋势报告、技术动态创新及市场预测
  3. 2021-2025年中国灯光调光开关行业市场供需与战略研究报告
  4. oracle 12c权限设置,如何设置 Oracle 数据库权限
  5. 金电联行程小龙:企业数字化转型的目标、决策与实践
  6. 数据库史上最大投资!Neo4j获3.25亿美元F轮融资
  7. “龙书”作者斩获图灵奖!谷歌 AI 大神、Swift 之父都受它启蒙
  8. 腾讯员工每年写3万行代码;马斯克承认利用摄像头监视车主;Chrome 89上线实时字幕 | 极客头条...
  9. 每位开发人员都应该阅读的优秀源代码,长啥样?
  10. @程序员,CSDN卫衣、背包、鼠标垫......福利来啦!!!