对于之前没有接触过该类型题目的人来说,此题无疑是个难题,本人提交了10次才正确通过,期间遇到了非常多的问题,感觉几乎把OJ的所有错误遍历了一遍,下面详细说说自己做该题的经验。

首先承认,我一开始并没有想到什么图模型,或者说是一点思路都没有。然后我就冥思苦想,首先想到了可以先构造一个二维矩阵,判断给定的词之间是否能两两一步到达,这一步可以通过两层循环加字符串的遍历完成,应该不难。获得这个矩阵之后,我居然还是没有想到图,只是在纸上写写画画感觉问题可以转化成在矩阵中搜索一条路径可以到达最后一行。路径搜索应该可以通过深搜完成,之后就开始按照这个思路写代码,结果越写越乱,遇到多次MLE。

多次尝试无果后,我感觉之前的思路不对,需要重整思路。然后又是写写画画,突然灵光一闪:搜索路径貌似可以用图表示!然后按照这个思路很快就想明白了整个流程:首先构造一个无向图用来表示单词之间的可达性,然后从表示起点的节点开始对整个图进行BFS遍历,直到找到表示end的节点。按照这个思路也很快写出代码,但是提交后又遇到新问题:不停地超时。此时说明算法已经正确,但是复杂度还是太高。不妨先看一下这时的代码:

public int ladderLength2(String start, String end, HashSet<String> dict) {
if (start == null || end == null || start.equals(end)
|| start.length() != end.length())
return 0; if (isOneWordDiff(start, end))
return 2; dict.add(start);
dict.add(end); String[] dicts = (String[]) dict.toArray(new String[0]); int size = dicts.length;   // 表示图的列表数组
ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>(); int s = 0, e = 0;
// 判断一个单词一步可以到达哪些单词
for (int i = 0; i < size; i++) {
if (start.equals(dicts[i]))
s = i;
if (end.equals(dicts[i]))
e = i; ArrayList<Integer> list = new ArrayList<Integer>();
for (int j = 0; j < size; j++) {
if (isOneWordDiff(dicts[i], dicts[j]))
list.add(j);
} lists.add(list);
} HashMap<Integer,Integer> dist = new HashMap<Integer, Integer>(); Queue<Integer> queue = new LinkedList<Integer>();
queue.add(s);
dist.put(s, 1); while (!queue.isEmpty()) {
int index = queue.poll();
ArrayList<Integer> list = lists.get(index); for (int i = 0; i < list.size(); i++) {
if (list.get(i) == e) {
return dist.get(index) + 1;
} if (!dist.containsKey(list.get(i))) {
queue.add(list.get(i));
dist.put(list.get(i), dist.get(index) + 1);
}
}
} return 0;
}
private boolean isOneWordDiff(String a, String b) {
int diff = 0;
for (int i = 0; i < a.length(); i++) {
if (a.charAt(i) != b.charAt(i)) {
diff++;
if (diff >= 2)
return false;
}
} return diff == 1;
}

分析一下上面代码的思路:

1.首先将start和end添加到词典中,并将词典转化成数组;

2.创建一个二维数组,二维数组的每一维表示某个单词可以通过一步转化到达的单词,也即利用邻接表的方式存储图结构。在这个过程中也获得了start和end代表的数字;

3.利用构造的图进行BFS遍历,直到遇到end节点或者返回0。在遍历的过程中,由于图的边长是1,所以我们在遍历的时候总是得到从start到某个节点的最短路径,所以我们只需要考虑尚未遍历过的顶点即可。

上述代码是正确的,但是一直超时真是让人搞不清状况。后来,只能上网搜索别人的解答才明白其中的原因。超时的地方不在BFS遍历,而是在我们构造图的地方。我们采用了两层遍历构造一个图,此时复杂度是O(n2),数据量很小时可能体现不出它的劣势,但是当n上千时(给定的测试集中有这样的例子),上面的方法构造图就显得太慢。

这里我们可以不用实际构造图,而在BFS遍历的时候去寻找当前单词可达的下一个单词。如果还是通过遍历所有的单词判断是否可达,则复杂度和上面一样,但实际上在上千个单词中,只有少数几个可以由当前单词一步到达,我们之前的比较浪费了很多时间在不可能的单词上。网上对该问题的解决无一例外都是按照下面的思路:将当前单词每一个字符替换成a~z的任意一个字符,然后判断是否在词典中出现。此时的复杂度是O(26*word_length),当单词比较短时,这种方法的优势就体现出来了。按照这种思路修改后的代码如下:

public int ladderLength(String start, String end, HashSet<String> dict) {
if (start == null || end == null || start.equals(end)
|| start.length() != end.length())
return 0; if (isOneWordDiff(start, end))
return 2; Queue<String> queue=new LinkedList<String>();
HashMap<String,Integer> dist=new HashMap<String,Integer>(); queue.add(start);
dist.put(start, 1); while(!queue.isEmpty())
{
String head=queue.poll(); int headDist=dist.get(head);
//从每一个位置开始替换成a~z
for(int i=0;i<head.length();i++)
{
for(char j='a';j<'z';j++)
{
if(head.charAt(i)==j) continue; StringBuilder sb=new StringBuilder(head);
sb.setCharAt(i, j); if(sb.toString().equals(end)) return headDist+1; if(dict.contains(sb.toString())&&!dist.containsKey(sb.toString()))
{
queue.add(sb.toString());
dist.put(sb.toString(), headDist+1);
}
}
}
} return 0;
   }

我们可以看出,代码更加简洁,而且效率也更高,提交上述代码就可以AC了。

leetcode之word ladder的更多相关文章

  1. Java for LeetCode 126 Word Ladder II 【HARD】

    Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...

  2. [LeetCode] 126. Word Ladder II 词语阶梯 II

    Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformat ...

  3. [LeetCode] 127. Word Ladder 单词阶梯

    Given two words (beginWord and endWord), and a dictionary's word list, find the length of shortest t ...

  4. LeetCode 126. Word Ladder II 单词接龙 II(C++/Java)

    题目: Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transfo ...

  5. [Leetcode Week5]Word Ladder II

    Word Ladder II 题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/word-ladder-ii/description/ Descripti ...

  6. [Leetcode Week5]Word Ladder

    Word Ladder题解 原创文章,拒绝转载 题目来源:https://leetcode.com/problems/word-ladder/description/ Description Give ...

  7. [LeetCode] 126. Word Ladder II 词语阶梯之二

    Given two words (beginWord and endWord), and a dictionary's word list, find all shortest transformat ...

  8. 【leetcode】Word Ladder

    Word Ladder Total Accepted: 24823 Total Submissions: 135014My Submissions Given two words (start and ...

  9. 【leetcode】Word Ladder II

      Word Ladder II Given two words (start and end), and a dictionary, find all shortest transformation ...

  10. [Leetcode][JAVA] Word Ladder II

    Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from ...

随机推荐

  1. Windows下使用Vim极简入门

    0.下载与安装 在vim官网下载 1.Vim常见的几种模式: 一般模式:主要用于浏览,不能随意删除.修改等.按Esc进入该模式. 插入模式:类似平常我们打开记事本后所在的模式.在命令模式下按i进入. ...

  2. APP自动化框架LazyAndroid使用手册(3)--核心API介绍

    作者:黄书力 概述 在前一篇博文中,简要介绍了一款安卓UI自动化测试框架LazyAndroid (http://blog.csdn.net/kaka1121/article/details/53204 ...

  3. 六星经典CSAPP-笔记(7)加载与链接(上)

    六星经典CSAPP-笔记(7)加载与链接 1.对象文件(Object File) 1.1 文件类型 对象文件有三种形式: 可重定位对象文件(Relocatable object file):包含二进制 ...

  4. linux网络编程之二-----多播(组播)编程

    多播编程实例 服务器端 下面是一个多播服务器的例子.多播服务器的程序设计很简单,建立一个数据包套接字,选定多播的IP地址和端口,直接向此多播地址发送数据就可以了.多播服务器的程序设计,不需要服务器加入 ...

  5. Scikit-learn:分类classification

    http://blog.csdn.net/pipisorry/article/details/53034340 支持向量机SVM分类 svm分类有多种不同的算法.SVM是非常流行的机器学习算法,主要用 ...

  6. JVM概述

    JVM是什么 JVM全称是Java Virtual Machine(java虚拟机).它之所以被称之为是"虚拟"的,就是因为它仅仅是由一个规范来定义的抽象计算机.我们平时经常使用的 ...

  7. Spark Scheduler模块源码分析之TaskScheduler和SchedulerBackend

    本文是Scheduler模块源码分析的第二篇,第一篇Spark Scheduler模块源码分析之DAGScheduler主要分析了DAGScheduler.本文接下来结合Spark-1.6.0的源码继 ...

  8. JVM基础知识GC

    在网上看到一篇很不错的讲解JVM GC的文章,看完之后觉得可以留着以后多看几遍便转载了下来.但是找了半天也没有找到原作者地址.抱歉不能标明原文地址了.以下是文章内容. 几年前写过一篇关于JVM调优的文 ...

  9. 剑指Offer——CVTE校招笔试题+知识点总结(Java岗)

    剑指Offer(Java岗)--CVTE校招笔试题+知识点总结 2016.9.3 19:00参加CVTE笔试,笔试内容如下: 需要掌握的知识:Linux基本命令.网络协议.数据库.数据结构. 选择题 ...

  10. android自定义view实现progressbar的效果

    一键清理是很多Launcher都会带有的功能,其效果也比较美观.实现方式也许有很多中,其中常见的是使用图片drawable来完成的,具体可以参考这篇文章:模仿实现360桌面水晶球式的一键清理特效.本文 ...