Java 算法-圖是否為樹(并查集或深搜)

??今天做了一道很有意思的一道題沙峻,這道題雖然難度只是中等滨彻,但是里面涉及到的東西卻是不少。其中,我在里面學(xué)習(xí)到了并查集這個(gè)東西逗余,雖然不是很深刻霍殴,至少有一個(gè)印象坟岔;還有深搜顶瞳,一直以來(lái),深搜和廣搜都是我的弱項(xiàng)赶促,本文的理解是基于別人的博客: lintcode178. graph valid tree 圖是否是樹液肌。我們來(lái)看看題

題意

給出 n 個(gè)節(jié)點(diǎn),標(biāo)號(hào)分別從 0 到 n - 1 并且給出一個(gè) 無(wú)向 邊的列表 (給出每
條邊的兩個(gè)頂點(diǎn)), 寫一個(gè)函數(shù)去判斷這張`無(wú)向`圖是否是一棵樹

樣例

給出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.

注意事項(xiàng)

你可以假設(shè)我們不會(huì)給出重復(fù)的邊在邊的列表當(dāng)中. 無(wú)向邊 [0, 1] 和 [1, 0] 
是同一條邊鸥滨, 因此他們不會(huì)同時(shí)出現(xiàn)在我們給你的邊的列表當(dāng)中嗦哆。

1.并查集

??首先有兩點(diǎn):

?? A.如果點(diǎn)的個(gè)數(shù)減去邊數(shù)不等于1,此圖肯定不為樹婿滓。
??B.如果有一條邊的兩個(gè)點(diǎn)同屬于一個(gè)集合的話老速,那么此圖肯定不為樹

??第一點(diǎn)我們非常容易的能夠判斷出來(lái),但是第二種怎么來(lái)判斷呢凸主?這就需要我們的并查集(我也是第一次接觸到并查集橘券,只是知道它的模型,所以可能說(shuō)的不是很清楚)。

(1).一維數(shù)組記錄每一個(gè)點(diǎn)的集合

??我們首先可以定義一個(gè)一維數(shù)組旁舰,默認(rèn)全部初始化為-1锋华,其中表示的意思就是:假設(shè)數(shù)組temp[], temp[0]表示的是0這個(gè)點(diǎn)屬于的集合,不同的集合我們不同數(shù)字來(lái)表示箭窜,比如毯焕,0集合和1集合是不同的,同一個(gè)集合的點(diǎn)構(gòu)成了一棵樹磺樱。
??具體的操作:
??當(dāng)我們遍歷到一條邊時(shí)纳猫,判斷這條邊的兩個(gè)點(diǎn)是否在temp數(shù)組中出現(xiàn),其中分為三種情況:
??A.兩個(gè)點(diǎn)均未出現(xiàn)竹捉,也就是兩個(gè)點(diǎn)對(duì)應(yīng)的temp數(shù)組的值是等于-1芜辕,那么,我們將這兩個(gè)點(diǎn)對(duì)應(yīng)的數(shù)組值更為兩點(diǎn)中最小的那個(gè)點(diǎn)(這里沒(méi)有限制活孩,最大也行物遇,主要是保證他們倆在同一個(gè)集合中)。
??B.一個(gè)點(diǎn)出現(xiàn)過(guò)憾儒,一個(gè)點(diǎn)未出現(xiàn),那么我們將未出現(xiàn)的那個(gè)點(diǎn)對(duì)應(yīng)的數(shù)組值更新為出現(xiàn)的那個(gè)點(diǎn)的數(shù)組值乃沙,這樣就保證了兩個(gè)點(diǎn)屬于同一個(gè)集合起趾。
??C.兩個(gè)點(diǎn)都出現(xiàn)過(guò),只是屬于不同的集合警儒,也就是說(shuō)训裆,兩個(gè)點(diǎn)對(duì)應(yīng)的數(shù)組值不相同,那么此時(shí)我們的操作是將兩個(gè)集合合并起來(lái)蜀铲,具體的操作是:因?yàn)槊總€(gè)集合里面的所有值都是相同边琉,那么我們將值較大的那個(gè)集合的值全部更新為另一個(gè)集合的值,比如有兩個(gè)集合分別是:{1,1}记劝,{2,2}变姨,更新過(guò)后就是:{1,1,1,1}。這樣能保證兩個(gè)集合合并起來(lái)后厌丑,構(gòu)成一個(gè)集合定欧。
??D.兩個(gè)點(diǎn)都出現(xiàn)過(guò),同時(shí)還屬于同一個(gè)集合怒竿,那么此圖肯定不為樹砍鸠。

代碼

public boolean validTree(int n, int[][] edges) {
        //當(dāng)點(diǎn)數(shù)減去邊數(shù)不等于1時(shí),肯定不為樹
        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];
            // 當(dāng)兩個(gè)點(diǎn)屬于同一個(gè)集合時(shí)耕驰,要么兩點(diǎn)沒(méi)有在任何集合里面爷辱,要么在同一個(gè)集合里面
            if (temp[node1] == temp[node2]) {
                //都沒(méi)有出現(xiàn)過(guò)
                if (temp[node1] == -1) {
                    temp[node1] = temp[node2] = Math.min(node1, node2);
                } else { //都出現(xiàn)過(guò),同時(shí)還屬于同一個(gè)集合
                    return false;
                }
            } else {
                // 當(dāng)兩個(gè)點(diǎn)都在集合里面,但是是在不同的集合里饭弓,更新集合
                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 { // 當(dāng)只有一個(gè)點(diǎn)在集合里面
                    if (temp[node1] != -1) {
                        temp[node2] = temp[node1];
                    } else {
                        temp[node1] = temp[node2];
                    }
                }
            }
        }
        return true;
    }

如圖所示

2.深搜遍歷

??深搜遍歷在這里主要作用是:我們尋找每一個(gè)點(diǎn)的父節(jié)點(diǎn)双饥,如果兩個(gè)點(diǎn)的父節(jié)點(diǎn)相同的話,那么此圖肯定不為樹示启。這里的理解上可能有一些問(wèn)題兢哭,我們看看下面的幾種情況:

(1).兩個(gè)點(diǎn)均是第一次出現(xiàn)。如圖:

(2).一個(gè)點(diǎn)是出現(xiàn)過(guò)的夫嗓,另一個(gè)點(diǎn)是第一次出現(xiàn)迟螺。如圖(提示一下,下面圖的描述錯(cuò)了舍咖,C的父親應(yīng)該是A):

(3).兩個(gè)點(diǎn)都有父親矩父,只是父親不相同,分為兩種情況:

(4).兩個(gè)點(diǎn)都出現(xiàn)過(guò)排霉,并且父親相同窍株,分為兩種情況:

代碼

private int dfs(int temp[], int node){
        //當(dāng)這個(gè)點(diǎn)不在有父親了,返回這個(gè)點(diǎn)
        if(temp[node] == -1){
            return node;
        }
        else //如果這點(diǎn)還有父親的話攻柠,那么就繼續(xù)遍歷這個(gè)點(diǎn)的父親
        {
            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]點(diǎn)的父親
            int node1 = dfs(temp, edges[i][0]);
            //獲取edges[i][1]點(diǎn)的父親
            int node2 = dfs(temp, edges[i][0]);
            //如果父親相同的話球订,肯定不為樹
            if(node1 == node2){
                return false;
            }
            //將node2的父親設(shè)置為node1
            temp[node2] = node1;
        }
        return true;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市瑰钮,隨后出現(xiàn)的幾起案子冒滩,更是在濱河造成了極大的恐慌,老刑警劉巖浪谴,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件开睡,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡苟耻,警方通過(guò)查閱死者的電腦和手機(jī)篇恒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)凶杖,“玉大人胁艰,你說(shuō)我怎么就攤上這事」倏ǎ” “怎么了蝗茁?”我有些...
    開(kāi)封第一講書人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)寻咒。 經(jīng)常有香客問(wèn)我哮翘,道長(zhǎng),這世上最難降的妖魔是什么毛秘? 我笑而不...
    開(kāi)封第一講書人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任饭寺,我火速辦了婚禮阻课,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘艰匙。我一直安慰自己限煞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布员凝。 她就那樣靜靜地躺著署驻,像睡著了一般。 火紅的嫁衣襯著肌膚如雪健霹。 梳的紋絲不亂的頭發(fā)上旺上,一...
    開(kāi)封第一講書人閱讀 51,562評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音糖埋,去河邊找鬼宣吱。 笑死,一個(gè)胖子當(dāng)著我的面吹牛瞳别,可吹牛的內(nèi)容都是我干的征候。 我是一名探鬼主播,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼祟敛,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼疤坝!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起馆铁,我...
    開(kāi)封第一講書人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤卒煞,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后叼架,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡衣撬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年乖订,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片具练。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡乍构,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出扛点,到底是詐尸還是另有隱情哥遮,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布陵究,位于F島的核電站眠饮,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏铜邮。R本人自食惡果不足惜仪召,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一寨蹋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧扔茅,春花似錦已旧、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至玖瘸,卻和暖如春秸讹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背店读。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工嗦枢, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人屯断。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓文虏,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親殖演。 傳聞我的和親對(duì)象是個(gè)殘疾皇子氧秘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,139評(píng)論 25 707
  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)趴久,斷路器丸相,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 原本對(duì)于畢業(yè)好像沒(méi)有太多的感覺(jué) 我由于生病錯(cuò)過(guò)一整個(gè)冬天的招聘會(huì) 后來(lái)也去過(guò)幾家公司面試 最后進(jìn)入了一家x公司做一...
    許我一個(gè)晴天閱讀 263評(píng)論 1 0
  • 秋天灭忠,紅艷艷的蘋果扒開(kāi)綠葉往外瞧;小紅燈籠似的棗子掛滿了枝頭座硕;像紫瑪 瑙的葡萄一串串地掛在葡萄架下弛作,真迷人呀!...
    蘭庭步月閱讀 344評(píng)論 0 0
  • 老林是市局的一科之長(zhǎng),職權(quán)不大华匾,來(lái)頭卻不小映琳。他的老泰山在退休之前是某局的一個(gè)副局長(zhǎng),推薦了不少人蜘拉,老林自然也在其中...
    蘇盧浮閱讀 198評(píng)論 0 1