百度2017年暑期实习生笔试题——单词接龙
来源:互联网 发布:华润燃气oa软件 编辑:程序博客网 时间:2024/05/16 07:01
题目来源:[编程题]单词接龙
这道题同时也是2016中兴捧月蓝剑之路挑战赛初赛模拟测试题,问题描述如下图:
测试用例如下图:
根据上面的TestCase 2的结果我们可以知道,对于输入单词的顺序我们是可以调整的,也就是说无论怎么调整单词的顺序,只要能形成接龙即可。
可能有人会想到通过调整单词的顺序,比如按首字母排序或按尾字母排序的方式对输入进行重新排序再依次检查首尾是否可以形成接龙,这样就掉入了本题的第一个陷阱。事实上,在本题中26个英文字母是没有所谓的先后顺序的,因为我们要判断的是这些单词能否形成一条接龙,即使你的首字母是a而我的首字母是z,但是你的单词是abc中而我的是单词zxa,你的单词仍然排在我的后面。
这里有人可能已经看出来了,如果把每个单词看成一条有向边,首尾字母看成边上的起点和终点,问题就转化成了判断有向图中是否可以表示为一条(不闭合的)欧拉路径或欧拉回路的一笔画问题。
根据有向图中欧拉路径的判定定理
一个连通的有向图可以表示为一条从起点到终点的(不闭合的)欧拉路径的充要条件是: 起点的出度比入度多1, 终点的入度比出度多1,而其它顶点的入度和出度都相等。
一个连通的有向图可以表示为一条欧拉回路的充要条件是:每个顶点的入度和出度都相等
注意到上面我对连通的三个字进行了加粗,目的是强调不要忘记判断有向图的连通性(这里只要满足弱连通即可),对于百度那道笔试题网上很多人只考虑到统计点的入度与出度来判断是否能形成接龙,而没有检验有向图的连通性,虽然这样的代码能通过牛客OJ上所有的测试用例,但实际上对于aba,cdc,efe这样的输入却会得到错误的输出"Yes",原因就是这些单词形成的有向图是不连通的。这也从侧面说明了牛客OJ上用例设计的不够全面。
中兴的比赛中官方已经为我们实现了主程序,只需要我们自己实现WordListOrder类的canArrangeWords方法即可,这里为了保证程序实现的完整性,我们以百度2017年暑期实习生笔试题为准,输入时首先给出单词的个数,再依次输入每个单词,输出"Yes"或"No",Java实现的源码如下:
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 = true; // 有狭义欧拉路径或欧拉回路标志 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';// 以第一个单词的首字母作为起点 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]; queue.offer(start); // 从起点开始进行广度优先搜索,把路过的边都拆掉 while(!queue.isEmpty()) { int currentVertex = queue.peek(); passedVertex[currentVertex] = true; queue.poll(); for(int vertex = 0; vertex < 26; vertex++) { if(undirectedGraph[currentVertex][vertex] == 1 && passedVertex[vertex] == false) { undirectedGraph[currentVertex][vertex] = 0; undirectedGraph[vertex][currentVertex] = 0; queue.offer(vertex); } } } int passedVertexNum = 0; for(int vertex = 0; vertex < 26; vertex++) { if(passedVertex[vertex]) passedVertexNum++; } // 遍历到所有的点,证明无向图是连通的 if(passedVertexNum == vertexNum) return true; else return false; }}
感谢@p101712911指出原程序中存在的bug,先前我把问题抽象成了无向图的一笔画问题,忽略了单词不能倒过来形成接龙的事实,对于某些特殊的输入比如:ca、ab、cb会得到错误的结果"Yes",改正后的程序把问题转化成有向图的一笔画问题并解决。
- 百度2017年暑期实习生笔试题——单词接龙(有向欧拉图)
- 百度2017年暑期实习生笔试题——单词接龙
- 百度17年暑期实习生笔试题 - 单词接龙
- 百度2017暑期实习生编程题-单词接龙
- 百度2017暑期实习生编程题:单词接龙
- 百度2017暑期实习生编程题单词接龙
- 百度笔试题——单词接龙
- 成语接龙--百度2017暑期实习生编程题
- 百度暑期实习生笔试
- 百度暑期实习生笔试
- 笔试题86. 百度笔试题——成语接龙
- 2017年暑期实习生招聘(百度)——两道编程题
- 2017年江苏电信暑期实习生笔试编程题
- 乐视2017暑期实习生笔试编程题
- 百度2017暑期实习生编程题
- 百度2017暑期实习生编程题
- 百度2017暑期实习生编程题
- 百度2017暑期实习生编程题
- SEO辅助神器:入驻搜狐自媒体100%成功的秘诀
- 矩形图表绘制
- 苹果推送机制(APNS)
- Activity启动模式
- iOS RabbitMQ集成及使用
- 百度2017年暑期实习生笔试题——单词接龙
- 显式动画
- android webview 快速实现office文档在线预览展示(doc,docx,xls,xlsx,ppt,pptx)
- JQuery 实现多个checkbox 只选中一个
- cmd及linux两个数相加
- 天纵智能软件快速开发列表+统计图分析插件
- 3Sum Closest
- Anroid studio遇到的问题3---INSTALL_FAILED_UPDATE_INCOMPATIBLE
- OpenCV学习笔记四:ImgProc模块