1.题目描述

Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) from start to end, such that:

 

Only one letter can be changed at a time

Each intermediate word must exist in the dictionary

For example,

 

Given:

start = "hit"

end = "cog"

dict = ["hot","dot","dog","lot","log"]

 

Return

 

  [

    ["hit","hot","dot","dog","cog"],

    ["hit","hot","lot","log","cog"]

  ]

2.解题思路

我一看到这个题目就觉得类似于最小生成树,应该用贪心算法来做,贪心算法的思路如下:

       从start串出发,找出一次变换可以得到的string串的集合S1,如果集合S1中包含有end串,那么搜索结束,否则,搜索两步之内能到达的串的集合S2,同样判断两步之内能到达的串集合中是否有end串,以此类推,最终找到最短路径。另外,路径保存需要单独设置一个数据结构,

最终算法描述如下(类最小生成树):

  1. 将字典dict中的所有字符串分为左右两侧,一侧为leftside=start(实际编码不需存储),一侧为rightside=(dict-start),当前距start最远的节点,比如说从start i 步之内可达的节点集合curStep = start (因为初始是0步可达)。
  2. 计算nextStep,也就是 i+1 步可达的字符串集合,最简单的思路就是下面的思路,遍历curStep 遍历rightside,逐个比较,必然能找到nextStep,找到nextStep之后curStep 变成了nextStep,将nextStep 中的字符串从rightside里面抹去,nextStep清空继续寻找直至找到的nextStep或rightside为空(表示没有路径到end),或者end被发现。

于是有了下面的这份代码:

class Solution {

public:

    vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {

        // end typing your C/C++ solution below

        // DO NOT write int main() function

        //areslipan@163.com

 

        map<string,vector<string> > path;

 

        unordered_set<string>leftside;

        unordered_set<string>rightside=dict;

        rightside.insert(start);

        rightside.insert(end);

 

        leftside.insert(start);

        rightside.erase(start);

 

        unordered_set<string>curStep;

        unordered_set<string>nextStep;

        curStep.insert(start);

        while(curStep.find(end)==curStep.end()&&!rightside.empty())

        {

            

            unordered_set<string>::iterator iter_us_cur;

            unordered_set<string>::iterator iter_us_right;

 

            for(iter_us_cur=curStep.begin();iter_us_cur!=curStep.end();++iter_us_cur)

            {

                

 

                for(iter_us_right=rightside.begin();iter_us_right!=rightside.end();++iter_us_right)

                {

                    

                    if(isCvtable(*iter_us_cur,*iter_us_right))

                    {

                        if(path.find(*iter_us_cur)!=path.end())

                        {

                            path[*iter_us_cur].push_back(*iter_us_right);

                        }

                        else

                        {

                            vector<string> emptyV;

                            path[*iter_us_cur]=emptyV;

                            path[*iter_us_cur].push_back(*iter_us_right);

                        }

 

                        nextStep.insert(*iter_us_right);

                    }

                }

 

            }

 

            if(nextStep.empty())break;

            for(iter_us_right=nextStep.begin();iter_us_right!=nextStep.end();++iter_us_right)

            {

                rightside.erase(*iter_us_right);

            }

            curStep = nextStep;

            nextStep.clear();

        }

 

        vector<vector<string> > result;

        vector<string> temp;

 

        if(curStep.find(end)!=curStep.end())

        {

            output(path,start,end,result,temp);

        }

 

        return result;

 

    }

    bool isCvtable(string str1,string str2)

    {

        //cout<<"isCvtable: "<<str1<<str2<<endl;

        if(str1.length()!=str2.length()){return false;}

        

        int count=0;

        for(int i = 0;i<str1.length();++i)

        {

            if(str1[i]!=str2[i])count++;

            if(count>1)return false;

        }

        

        return count==1;

    }

 

 

    void output(map<string,vector<string> >&path,string start,string end,vector<vector<string> >&result,vector<string> & temp)

    {

        temp.push_back(start);

 

        if(start==end)

        {

            result.push_back(temp);return;

        }

 

        vector<string>::iterator iter_v;

        

        for(iter_v=path[start].begin();iter_v!=path[start].end();++iter_v)

        {

            output(path,*iter_v,end,result,temp);temp.pop_back();

        }

    }

};

 

提交online judge之后,小数据集没问题,大数据集却TLE了,分析了一下,主要是从curStep求nextStep的过程太耗时,我这个是O(N2)的时间复杂度,结果如下:

挂掉的这个案例大概有3000个词,很大,分析了一下,题目给的参数是unordered_set是有用意的,unordered_set实际底层是个hash表,所以能够常数时间索引一个字符串,基于这个思路,在已知curStep、rightside求nextStep的过程中:

        对每一个curStep中的字符串,假设长度为M,那么它的每位有25种变化,也就是每个单词有25*M中变化,那么时间复杂度就变成了O(MN),单词长度一般不会太大,所以这个是个线性的算法,分析完毕,我开始着手写算法:

class Solution {

public:

    vector<vector<string> > findLadders(string start, string end, unordered_set<string> &dict) {

        // end typing your C/C++ solution below

        // DO NOT write int main() function

        //areslipan@163.com

 

        map<string,vector<string> > path;

 

        unordered_set<string>rightside=dict;

 

        rightside.erase(start);

        

        unordered_set<string>curStep;

        unordered_set<string>nextStep;

        curStep.insert(start);

        while(curStep.find(end)==curStep.end()&&!rightside.empty())

        {

            unordered_set<string>::iterator iter_us_cur;

            for(iter_us_cur=curStep.begin();iter_us_cur!=curStep.end();++iter_us_cur)

            {

                string temp;

                for(int i=0;i<(*iter_us_cur).length();++i)

                {

                    for(int j = 0;j<26;j++)

                    {

                        temp = *iter_us_cur;

                        if(temp[i]!=('a'+j))

                        {

                            temp[i] = ('a'+j);

                        }

                        

                        if(rightside.count(temp)==1)

                        {

                            nextStep.insert(temp);

                            if(path.find(*iter_us_cur)==path.end())

                            {

                                vector<string> emptyV;

                                path.insert(make_pair(*iter_us_cur,emptyV));

                            }

                            

                            path[*iter_us_cur].push_back(temp);

                        }

                    }                    

                }

            }

            

            if(nextStep.empty())break;

            unordered_set<string>::iterator iter_set;

            for(iter_set=nextStep.begin();iter_set!=nextStep.end();++iter_set)

            {

                rightside.erase(*iter_set);

            }

            curStep = nextStep;

            nextStep.clear();

        }

        

        vector<vector<string> > result;

        vector<string> temp;

        

        if(curStep.find(end)!=curStep.end())

        {

            output(path,start,end,result,temp);

        }

 

        return result;

 

    }

    

    void output(map<string,vector<string> >&path,string start,string end,vector<vector<string> >&result,vector<string> & temp)

    {

        temp.push_back(start);

 

        if(start==end)

        {

            result.push_back(temp);return;

        }

 

        vector<string>::iterator iter_v;

        

        for(iter_v=path[start].begin();iter_v!=path[start].end();++iter_v)

        {

            output(path,*iter_v,end,result,temp);temp.pop_back();

        }

    }

};

 

结果出来的一瞬间很美妙:

另外,输出结果的方式也有改进的余地,如图所示,程序中的path实际是这么一张图,实际就是一张邻接表。

我的算法是从start开始深度搜索,直至找到end,当搜索到的最后一个节点不是end的时候其实都是无效搜索(而且比重很大),所以可以把上述这幅图反过来,然后从end开始反向搜索,以空间换时间。

leetcode—word ladder II的更多相关文章

  1. [leetcode]Word Ladder II @ Python

    [leetcode]Word Ladder II @ Python 原题地址:http://oj.leetcode.com/problems/word-ladder-ii/ 参考文献:http://b ...

  2. LeetCode :Word Ladder II My Solution

    Word Ladder II Total Accepted: 11755 Total Submissions: 102776My Submissions Given two words (start  ...

  3. LeetCode: Word Ladder II 解题报告

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

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

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

  5. LeetCode: Word Ladder II [127]

    [题目] Given two words (start and end), and a dictionary, find all shortest transformation sequence(s) ...

  6. [LeetCode] Word Ladder II

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

  7. LeetCode:Word Ladder I II

    其他LeetCode题目欢迎访问:LeetCode结题报告索引 LeetCode:Word Ladder Given two words (start and end), and a dictiona ...

  8. [Leetcode Week5]Word Ladder II

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

  9. 【leetcode】Word Ladder II

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

随机推荐

  1. Shell命令合集

    Ccat zdd 浏览文件zdd的内容cat zdd1 zdd2 浏览多个文件的内容cat -n zdd浏览文件zdd的内容并显示行号 cd 回到起始目录,也即刚登陆到系统的目录,cd后面无参数cd ...

  2. POJ 2275 Flipping Pancake

    点我看题目 题意 : 按我自己的理解就是,给你n个数,按照从上到下排列,现在让你进行一系列的操作,让你将数按照从大到小排好. 思路 : 比赛的时候以为要用记录路径的搜索,当时没什么把握,所以没做,今天 ...

  3. poj 3440 Coin Toss 概率问题

    这题主要是推导数学公式!!! 将概率问题转化为圆心所在的面积! 代码如下: #include<iostream> #include<stdio.h> #include<a ...

  4. nginx如何解决超长请求串

    nginx是一个强大的http服务器,但是在使用过程中发现,当遇到超长的post请求或者get请求时,nginx会返回413.400.414等状态码,这是因为请求串长度超过了nginx默认的缓存大小或 ...

  5. JVM并发机制的探讨——内存模型、内存可见性和指令重排序

    并发本来就是个有意思的问题,尤其是现在又流行这么一句话:“高帅富加机器,穷矮搓搞优化”. 从这句话可以看到,无论是高帅富还是穷矮搓都需要深入理解并发编程,高帅富加多了机器,需要协调多台机器或者多个CP ...

  6. http://doc.okbase.net/congcong68/archive/112508.html

    http://doc.okbase.net/congcong68/archive/112508.html

  7. ajax readyState的五种状态详解

    通过ajax的readyState的值,我们可以知道当前的这个http请求处于什么状态.对于web的调试是比较重要的. readyState 状态说明: (0)未初始化 此阶段确认XMLHttpReq ...

  8. Servlet课程0426(十二)Servlet MV模式下用户登录及查看用户表中所有用户

    Welcome.java //登录界面 package com.tsinghua; import javax.servlet.http.*; import java.io.*; import java ...

  9. 这些废弃的 HTML 标签不要用

    HTML 已经发展了多年,现在 W3C 已经发布了 HTML 5.1 的提案推荐标准,一些陈旧废弃的标签已经在后继的标准中逐渐消失.这里为大家列出那些已经被废弃 HTML 标签,看看你是不是还在使用它 ...

  10. java:I/O 根据用户输入反馈信息

    import java.io.*; class userInputIO{ //Java中成员变量有默认初始化,也就是如果不显式设置初始值的话就会被初始化为其类型的默认值(0.false.null等). ...