Java 算法-图是否为树(并查集或深搜)

  今天做了一道很有意思的一道题,这道题虽然难度只是中等,但是里面涉及到的东西却是不少。其中,我在里面学习到了并查集这个东西,虽然不是很深刻,至少有一个印象;还有深搜,一直以来,深搜和广搜都是我的弱项,本文的理解是基于别人的博客: lintcode178. graph valid tree 图是否是树。我们来看看题

题意

给出 n 个节点,标号分别从 0 到 n - 1 并且给出一个 无向 边的列表 (给出每
条边的两个顶点), 写一个函数去判断这张`无向`图是否是一棵树

样例

给出n = 5 并且 edges = [[0, 1], [0, 2], [0, 3], [1, 4]], 返回 true.
给出n = 5 并且 edges = [[0, 1], [1, 2], [2, 3], [1, 3], [1, 4]], 返回 false.

注意事项

你可以假设我们不会给出重复的边在边的列表当中. 无向边 [0, 1] 和 [1, 0] 
是同一条边, 因此他们不会同时出现在我们给你的边的列表当中。

1.并查集

  首先有两点:

   A.如果点的个数减去边数不等于1,此图肯定不为树。
  B.如果有一条边的两个点同属于一个集合的话,那么此图肯定不为树

  第一点我们非常容易的能够判断出来,但是第二种怎么来判断呢?这就需要我们的并查集(我也是第一次接触到并查集,只是知道它的模型,所以可能说的不是很清楚)。

(1).一维数组记录每一个点的集合

  我们首先可以定义一个一维数组,默认全部初始化为-1,其中表示的意思就是:假设数组temp[], temp[0]表示的是0这个点属于的集合,不同的集合我们不同数字来表示,比如,0集合和1集合是不同的,同一个集合的点构成了一棵树。
  具体的操作:
  当我们遍历到一条边时,判断这条边的两个点是否在temp数组中出现,其中分为三种情况:
  A.两个点均未出现,也就是两个点对应的temp数组的值是等于-1,那么,我们将这两个点对应的数组值更为两点中最小的那个点(这里没有限制,最大也行,主要是保证他们俩在同一个集合中)。
  B.一个点出现过,一个点未出现,那么我们将未出现的那个点对应的数组值更新为出现的那个点的数组值,这样就保证了两个点属于同一个集合。
  C.两个点都出现过,只是属于不同的集合,也就是说,两个点对应的数组值不相同,那么此时我们的操作是将两个集合合并起来,具体的操作是:因为每个集合里面的所有值都是相同,那么我们将值较大的那个集合的值全部更新为另一个集合的值,比如有两个集合分别是:{1,1},{2,2},更新过后就是:{1,1,1,1}。这样能保证两个集合合并起来后,构成一个集合。
  D.两个点都出现过,同时还属于同一个集合,那么此图肯定不为树。

代码

public boolean validTree(int n, int[][] edges) {
        //当点数减去边数不等于1时,肯定不为树
        if (n - edges.length != 1) {
            return false;
        }
        int temp[] = new int[n];
        for (int i = 0; i < edges.length; i++) {
            int node1 = edges[i][0];
            int node2 = edges[i][1];
            // 当两个点属于同一个集合时,要么两点没有在任何集合里面,要么在同一个集合里面
            if (temp[node1] == temp[node2]) {
                //都没有出现过
                if (temp[node1] == -1) {
                    temp[node1] = temp[node2] = Math.min(node1, node2);
                } else { //都出现过,同时还属于同一个集合
                    return false;
                }
            } else {
                // 当两个点都在集合里面,但是是在不同的集合里,更新集合
                if (temp[node1] != -1 && temp[node2] != -1) {
                    int max = Math.max(temp[node1], temp[node2]);
                    int min = Math.min(temp[node1], temp[node2]);
                    for (int j = 0; j < n; j++) {
                        if (temp[j] == max) { //将值较大的集合的值全部更新min
                            temp[j] = min;
                        }
                    }
                } else { // 当只有一个点在集合里面
                    if (temp[node1] != -1) {
                        temp[node2] = temp[node1];
                    } else {
                        temp[node1] = temp[node2];
                    }
                }
            }
        }
        return true;
    }

如图所示

2.深搜遍历

  深搜遍历在这里主要作用是:我们寻找每一个点的父节点,如果两个点的父节点相同的话,那么此图肯定不为树。这里的理解上可能有一些问题,我们看看下面的几种情况:

(1).两个点均是第一次出现。如图:

(2).一个点是出现过的,另一个点是第一次出现。如图(提示一下,下面图的描述错了,C的父亲应该是A):

(3).两个点都有父亲,只是父亲不相同,分为两种情况:

(4).两个点都出现过,并且父亲相同,分为两种情况:

代码

private int dfs(int temp[], int node){
        //当这个点不在有父亲了,返回这个点
        if(temp[node] == -1){
            return node;
        }
        else //如果这点还有父亲的话,那么就继续遍历这个点的父亲
        {
            return dfs(temp, temp[node]);
        }
    }
    public boolean validTree(int n, int[][] edges) {

        if (n - edges.length != 1) {
            return false;
        }
        int []temp = new int[n];
        Arrays.fill(temp,-1);
        for(int i = 0; i < edges.length; i++){
            //获取edges[i][0]点的父亲
            int node1 = dfs(temp, edges[i][0]);
            //获取edges[i][1]点的父亲
            int node2 = dfs(temp, edges[i][0]);
            //如果父亲相同的话,肯定不为树
            if(node1 == node2){
                return false;
            }
            //将node2的父亲设置为node1
            temp[node2] = node1;
        }
        return true;
    }
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,088评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,715评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,361评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,099评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 60,987评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,063评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,486评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,175评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,440评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,518评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,305评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,190评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,550评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,880评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,152评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,451评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,637评论 2 335

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,042评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,490评论 18 139
  • 原本对于毕业好像没有太多的感觉 我由于生病错过一整个冬天的招聘会 后来也去过几家公司面试 最后进入了一家x公司做一...
    许我一个晴天阅读 256评论 1 0
  • 秋天,红艳艳的苹果扒开绿叶往外瞧;小红灯笼似的枣子挂满了枝头;像紫玛 瑙的葡萄一串串地挂在葡萄架下,真迷人呀!...
    兰庭步月阅读 343评论 0 0
  • 老林是市局的一科之长,职权不大,来头却不小。他的老泰山在退休之前是某局的一个副局长,推荐了不少人,老林自然也在其中...
    苏卢浮阅读 193评论 0 1