百度2016年暑期实习生笔试题 —— 单词接龙

拉姆刚开始学习英文单词,对单词排序很感兴趣。如果给拉姆一组单词,他能够迅速确定是否可以将这些单词排列在一个列表中,使得该列表中任何单词的首字母与前一单词的尾字母相同。你能编写一个程序来帮助拉姆进行判断吗?

输入描述:
输入包含多组测试数据。对于每组测试数据,第一行为一个正整数n,代表有n个单词。然后有n个字符串,代表n个单词。保证:2<=n<=200,每个单词长度大于1且小于等于10,且所有单词都是由小写字母组成。
输出描述:
对于每组数据,输出"Yes"或"No"

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

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

由题意可知,对于输入单词的顺序我们是可以调整的,也就是说无论怎么调整单词的顺序,只要能形成接龙即可

可能有人会想到通过调整单词的顺序,比如按首字母或尾字母对输入的单词进行重新排序再依次检查首尾是否可以形成接龙,这样就掉入了本题的第一个陷阱。事实上,在本题中26个英文字母是没有所谓的先后顺序的,因为我们要判断的是这些单词能否形成一条接龙,即使你的首字母是a而我的首字母是z,但是你的单词是abc中而我的是单词zxa,你的单词仍然排在我的后面。

这里有人可能已经看出来了,如果把每个单词看成一条有向边,首尾字母看成边上的起点和终点,问题就转化成了判断一个有向图是否可以表示为一条(不闭合的)欧拉路径或欧拉回路的一笔画问题

根据有向图中欧拉路径的判定定理
  一个连通的有向图可以表示为一条从起点到终点的(不闭合的)欧拉路径的充要条件是: 起点的出度比入度多1, 终点的入度比出度多1,而其它顶点的入度和出度都相等。
  一个连通的有向图可以表示为一条欧拉回路的充要条件是:每个顶点的入度和出度都相等

注意到上面我对连通的三个字进行了加粗,目的是强调不要忘记判断有向图的连通性(这里只要满足弱连通即可),对于百度那道笔试题网上很多人只考虑到统计点的入度与出度来判断是否能形成接龙,而没有检验有向图的连通性,虽然这样的代码能通过牛客OJ上所有的测试用例,但实际上对于aba,cdc,efe这样的输入却会得到错误的输出"Yes",原因就是这些单词形成的有向图是不连通的。这也从侧面说明了牛客OJ上用例设计的不够全面。
源码如下:

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个点,用整数0-25来表示
        int[][] directedGraph = new int [26][26];// 邻接矩阵表示有向图
        int[] inDegree = new int [26];           // 顶点入度
        int[] outDegree = new int [26];          // 顶点出度
        boolean[] hasLetter = new boolean[26];   // 标记字母是否出现过
        boolean hasEuler = false;                 // 有狭义欧拉路径或欧拉回路标志
        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)    // 起点
                startNum++;                    
            if(inDegree[vertex] - outDegree[vertex] == 1)    // 终点
                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;    // 统计图中点的个数
        for(int letter = 0; letter < 26; letter++)
        {
            if(hasLetter[letter])    
                vertexNum++;
        }
        int firstWordFirstLetter = arr[0].charAt(0) - 'a';// 以第一个单词的首字母作为起点进行BFS
        hasEuler = hasEuler && isConnected(firstWordFirstLetter, vertexNum, directedGraph);
        if(hasEuler)
            return "Yes";
        else
            return "No";
    }

    // 判断有向图是否弱连通,即转换成无向图判断是否连通
    public static boolean isConnected(int start, int vertexNum, int[][] directedGraph)
    {
        int[][] undirectedGraph = new int[26][26];
        for(int i = 0; i < 26; i++)     // 把有向图转换成无向图
        {
            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);
        // 从起点开始进行BFS,统计遍历到点的个数
        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);
            }
        }
        // 遍历到所有的点,证明无向图是连通的
        if(passedVertexNum == vertexNum)
            return true;
        else 
            return false;
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容

  • 1、用C语言实现一个revert函数,它的功能是将输入的字符串在原串上倒序后返回。 2、用C语言实现函数void ...
    希崽家的小哲阅读 6,098评论 0 12
  • 搁在一角的吉他早已落满了灰尘,尘封的记忆又一次的被唤醒。那一年,最好的你遇见了我,而我在最好的时候失去你。两个最好...
    霸屏怎么招阅读 324评论 0 0
  • 顺时针的倒退,是反方向堆积的自己。 回首极望而去, 苦难欢喜,交织过后, 遭遇过卡顿, 最终还是一咔一嚓的过来了。...
    许久久99阅读 284评论 0 0
  • 1 在知乎上看到这个一个提问: 我和男友都是准研究生,有家教和做项目的收入。恋爱近两年,他并没有送过我什么像样的礼...
    微书舍阅读 1,254评论 0 0
  • 六年前,二十岁的我低调地参加了全国高考,九百六十年前,二十岁的苏轼高调地参加了全国高考。 临走前,志气满满地告别敲...
    子玉作诗词阅读 686评论 0 7