百度2016年暑期實(shí)習(xí)生筆試題 —— 單詞接龍

拉姆剛開始學(xué)習(xí)英文單詞说敏,對單詞排序很感興趣鸥跟。如果給拉姆一組單詞,他能夠迅速確定是否可以將這些單詞排列在一個列表中盔沫,使得該列表中任何單詞的首字母與前一單詞的尾字母相同医咨。你能編寫一個程序來幫助拉姆進(jìn)行判斷嗎?

輸入描述:
輸入包含多組測試數(shù)據(jù)架诞。對于每組測試數(shù)據(jù)拟淮,第一行為一個正整數(shù)n,代表有n個單詞谴忧。然后有n個字符串很泊,代表n個單詞。保證:2<=n<=200沾谓,每個單詞長度大于1且小于等于10委造,且所有單詞都是由小寫字母組成。
輸出描述:
對于每組數(shù)據(jù)均驶,輸出"Yes"或"No"

輸入例子1:
3
abc
cdefg
ghijkl
輸出例子1:
Yes

輸入例子2:
4
abc
cdef
fghijk
xyz
輸出例子2:
No

由題意可知昏兆,對于輸入單詞的順序我們是可以調(diào)整的,也就是說無論怎么調(diào)整單詞的順序妇穴,只要能形成接龍即可爬虱。

可能有人會想到通過調(diào)整單詞的順序,比如按首字母或尾字母對輸入的單詞進(jìn)行重新排序再依次檢查首尾是否可以形成接龍腾它,這樣就掉入了本題的第一個陷阱跑筝。事實(shí)上,在本題中26個英文字母是沒有所謂的先后順序的携狭,因?yàn)槲覀円袛嗟氖沁@些單詞能否形成一條接龍继蜡,即使你的首字母是a而我的首字母是z,但是你的單詞是abc中而我的是單詞zxa逛腿,你的單詞仍然排在我的后面稀并。

這里有人可能已經(jīng)看出來了,如果把每個單詞看成一條有向邊单默,首尾字母看成邊上的起點(diǎn)和終點(diǎn)碘举,問題就轉(zhuǎn)化成了判斷一個有向圖是否可以表示為一條(不閉合的)歐拉路徑或歐拉回路的一筆畫問題

根據(jù)有向圖中歐拉路徑的判定定理
  一個連通的有向圖可以表示為一條從起點(diǎn)到終點(diǎn)的(不閉合的)歐拉路徑的充要條件是: 起點(diǎn)的出度比入度多1搁廓, 終點(diǎn)的入度比出度多1引颈,而其它頂點(diǎn)的入度和出度都相等耕皮。
  一個連通的有向圖可以表示為一條歐拉回路的充要條件是:每個頂點(diǎn)的入度和出度都相等

注意到上面我對連通的三個字進(jìn)行了加粗,目的是強(qiáng)調(diào)不要忘記判斷有向圖的連通性(這里只要滿足弱連通即可)蝙场,對于百度那道筆試題網(wǎng)上很多人只考慮到統(tǒng)計點(diǎn)的入度與出度來判斷是否能形成接龍凌停,而沒有檢驗(yàn)有向圖的連通性,雖然這樣的代碼能通過攀勐耍客OJ上所有的測試用例罚拟,但實(shí)際上對于aba,cdc完箩,efe這樣的輸入?yún)s會得到錯誤的輸出"Yes"赐俗,原因就是這些單詞形成的有向圖是不連通的。這也從側(cè)面說明了疟字客OJ上用例設(shè)計的不夠全面阻逮。
源碼如下:

import java.util.LinkedList;
import java.util.Queue;
import java.util.Scanner;

public class Main 
{

    public static void main(String[] args) 
    {
        // TODO Auto-generated method stub
        Scanner scan = new Scanner(System.in);
        while(scan.hasNext())
        {
            int n = scan.nextInt();
            String[] arr = new String[n];
            for(int i = 0; i < n ; i++)
                arr[i] = scan.next();
            System.out.println(WordListOrder.canArrangeWords(n, arr));
        }
        scan.close();
    }

}

class WordListOrder {

    public static String canArrangeWords(int n, String[] arr)
    {
        // 26個英文字母看作26個點(diǎn),用整數(shù)0-25來表示
        int[][] directedGraph = new int [26][26];// 鄰接矩陣表示有向圖
        int[] inDegree = new int [26];           // 頂點(diǎn)入度
        int[] outDegree = new int [26];          // 頂點(diǎn)出度
        boolean[] hasLetter = new boolean[26];   // 標(biāo)記字母是否出現(xiàn)過
        boolean hasEuler = false;                 // 有狹義歐拉路徑或歐拉回路標(biāo)志
        for(int i = 0; i < n; i++)
        {
            String word = arr[i];
            char firstLetter = word.charAt(0);
            char lastLetter = word.charAt(word.length()-1);
            outDegree[firstLetter - 'a']++;
            inDegree[lastLetter - 'a']++;
            directedGraph[firstLetter - 'a'][lastLetter - 'a'] = 1; // 有向圖
            hasLetter[firstLetter - 'a'] = true;
            hasLetter[lastLetter - 'a'] = true;
        }
        int startNum = 0;        
        int endNum = 0;
        for (int vertex = 0; vertex < 26; vertex++)
        {
            if(outDegree[vertex] - inDegree[vertex] == 1)    // 起點(diǎn)
                startNum++;                    
            if(inDegree[vertex] - outDegree[vertex] == 1)    // 終點(diǎn)
                endNum++;
            if(Math.abs(inDegree[vertex] - outDegree[vertex]) > 1)
            {
                hasEuler = false;
                break;
            }
        }
        boolean isEulerPath = (startNum == 1 && endNum == 1);   // 這里指狹義上的歐拉路徑,不包括歐拉回路
        boolean isEulerCircuit = (startNum == 0 && endNum == 0);// 歐拉回路
        if((!isEulerPath) && (!isEulerCircuit))    // 既不是歐拉路徑也不是歐拉回路
            hasEuler = false;
        // 判斷是否弱連通
        int vertexNum = 0;    // 統(tǒng)計圖中點(diǎn)的個數(shù)
        for(int letter = 0; letter < 26; letter++)
        {
            if(hasLetter[letter])    
                vertexNum++;
        }
        int firstWordFirstLetter = arr[0].charAt(0) - 'a';// 以第一個單詞的首字母作為起點(diǎn)進(jìn)行BFS
        hasEuler = hasEuler && isConnected(firstWordFirstLetter, vertexNum, directedGraph);
        if(hasEuler)
            return "Yes";
        else
            return "No";
    }

    // 判斷有向圖是否弱連通秩彤,即轉(zhuǎn)換成無向圖判斷是否連通
    public static boolean isConnected(int start, int vertexNum, int[][] directedGraph)
    {
        int[][] undirectedGraph = new int[26][26];
        for(int i = 0; i < 26; i++)     // 把有向圖轉(zhuǎn)換成無向圖
        {
            for(int j = 0; j < 26; j++) 
            {
                if(directedGraph[i][j] == 1)
                {
                    undirectedGraph[i][j] = 1;
                    undirectedGraph[j][i] = 1;
                }
            }
        }
        Queue<Integer> queue = new LinkedList<Integer>();
        boolean[] passedVertex = new boolean[26];
        int passedVertexNum = 0;
        queue.offer(start);
        // 從起點(diǎn)開始進(jìn)行BFS叔扼,統(tǒng)計遍歷到點(diǎn)的個數(shù)
        while(!queue.isEmpty())
        {
            int currentVertex = queue.poll();
            passedVertex[currentVertex] = true;
            passedVertexNum++;
            for(int vertex = 0; vertex < 26; vertex++)
            {
                if(undirectedGraph[currentVertex][vertex] == 1 && passedVertex[vertex] == false)
                    queue.offer(vertex);
            }
        }
        // 遍歷到所有的點(diǎn),證明無向圖是連通的
        if(passedVertexNum == vertexNum)
            return true;
        else 
            return false;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末漫雷,一起剝皮案震驚了整個濱河市币励,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌珊拼,老刑警劉巖食呻,帶你破解...
    沈念sama閱讀 219,270評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異澎现,居然都是意外死亡仅胞,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,489評論 3 395
  • 文/潘曉璐 我一進(jìn)店門剑辫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來干旧,“玉大人,你說我怎么就攤上這事妹蔽∽得校” “怎么了?”我有些...
    開封第一講書人閱讀 165,630評論 0 356
  • 文/不壞的土叔 我叫張陵胳岂,是天一觀的道長编整。 經(jīng)常有香客問我,道長乳丰,這世上最難降的妖魔是什么掌测? 我笑而不...
    開封第一講書人閱讀 58,906評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮产园,結(jié)果婚禮上汞斧,老公的妹妹穿的比我還像新娘夜郁。我一直安慰自己,他們只是感情好粘勒,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,928評論 6 392
  • 文/花漫 我一把揭開白布竞端。 她就那樣靜靜地躺著,像睡著了一般庙睡。 火紅的嫁衣襯著肌膚如雪婶熬。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,718評論 1 305
  • 那天埃撵,我揣著相機(jī)與錄音,去河邊找鬼虽另。 笑死暂刘,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的捂刺。 我是一名探鬼主播谣拣,決...
    沈念sama閱讀 40,442評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼族展!你這毒婦竟也來了森缠?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,345評論 0 276
  • 序言:老撾萬榮一對情侶失蹤仪缸,失蹤者是張志新(化名)和其女友劉穎贵涵,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體恰画,經(jīng)...
    沈念sama閱讀 45,802評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡宾茂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,984評論 3 337
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了拴还。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片跨晴。...
    茶點(diǎn)故事閱讀 40,117評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖片林,靈堂內(nèi)的尸體忽然破棺而出端盆,到底是詐尸還是另有隱情,我是刑警寧澤费封,帶...
    沈念sama閱讀 35,810評論 5 346
  • 正文 年R本政府宣布焕妙,位于F島的核電站,受9級特大地震影響弓摘,放射性物質(zhì)發(fā)生泄漏访敌。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,462評論 3 331
  • 文/蒙蒙 一衣盾、第九天 我趴在偏房一處隱蔽的房頂上張望寺旺。 院中可真熱鬧爷抓,春花似錦、人聲如沸阻塑。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,011評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽陈莽。三九已至渤昌,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間走搁,已是汗流浹背独柑。 一陣腳步聲響...
    開封第一講書人閱讀 33,139評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留私植,地道東北人忌栅。 一個月前我還...
    沈念sama閱讀 48,377評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像曲稼,于是被迫代替她去往敵國和親索绪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,060評論 2 355

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

  • 1贫悄、用C語言實(shí)現(xiàn)一個revert函數(shù)瑞驱,它的功能是將輸入的字符串在原串上倒序后返回。 2窄坦、用C語言實(shí)現(xiàn)函數(shù)void ...
    希崽家的小哲閱讀 6,272評論 0 12
  • 擱在一角的吉他早已落滿了灰塵唤反,塵封的記憶又一次的被喚醒。那一年鸭津,最好的你遇見了我拴袭,而我在最好的時候失去你。兩個最好...
    霸屏怎么招閱讀 339評論 0 0
  • 順時針的倒退曙博,是反方向堆積的自己拥刻。 回首極望而去, 苦難歡喜父泳,交織過后般哼, 遭遇過卡頓, 最終還是一咔一嚓的過來了惠窄。...
    許久久99閱讀 302評論 0 0
  • 1 在知乎上看到這個一個提問: 我和男友都是準(zhǔn)研究生蒸眠,有家教和做項(xiàng)目的收入。戀愛近兩年杆融,他并沒有送過我什么像樣的禮...
    微書舍閱讀 1,316評論 0 0
  • 六年前楞卡,二十歲的我低調(diào)地參加了全國高考,九百六十年前,二十歲的蘇軾高調(diào)地參加了全國高考蒋腮。 臨走前淘捡,志氣滿滿地告別敲...
    子玉作詩詞閱讀 737評論 0 7