给出两个单词(start和end)与一个字典,找出从start到end的最短转换序列。规则如下:

  • 一次只能改变一个字母
  • 中间单词必须在字典里存在

例如:

给出

start = "hit"
end =
"cog"
dict =
["hot","dot","dog","lot","log"]

返回

[

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

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

]

注意

  • 所有单词的长度一样
  • 所有单词中只有小写字母

 

初始思路

最直接的想法是从start开始,对每个字母位置从'a'到'z'尝试替换。如果替换字母后的单词在字典中,将其加入路径,然后以新单词为起点进行递归调用,否则继续循环。每层递归函数终止的条件是end出现或者单词长度*26次循环完毕。end出现时表示找到一个序列,对比当前最短序列做相应更新即可。

处理过程中需要注意的主要有几点:

  • 不能相同字母替换,如hot第一个位置遍历到h时不应该处理。否则就会不断的在hot上死循环。因此在替换后前要做一次检查。
  • 我们要找的是最短的转换方案,所以转换序列不应该出现重复的单词。否则组合将会有无数多种,如例子中的["hit","hot","dot","dog","dot","dog","dog",....."cog"]。这里我们可以使用一个unordered_set容器来保存某次一次替换序列中已出现过的单词,也可以每次使用std:find去搜索当前替换序列。如果使用unordered_set,在递归处理时,和单词序列一样,要在递归后做相应的出栈操作。
  • 处理过程中如果发现当前处理序列长度已经超过当前最短序列长度,可以中止对该序列的处理,因为我们要找的是最短的序列。
  1 class Solution {
  2 public:
  3     std::vector<std::vector<std::string>> findLadders(std::string start, std::string end, std::unordered_set<std::string> &dict)
  4     {
  5         std::vector<std::vector<std::string>> result;
  6         std::vector<std::string> entry;
  7         
  8         entry.push_back(start);
  9         Find(start, end, dict, 0, result, entry);
 10         
 11         return result;
 12     }
 13     
 14 private:
 15     void Find(std::string& start, const std::string& end, const std::unordered_set<std::string> &dict
 16               , size_t positionToChange, std::vector<std::vector<std::string>>& result, std::vector<std::string>& entry)
 17     {
 18         //如果长度已经等于当前结果中的长度,再找出来肯定就
 19                 //超过了,终止处理
 20         if(!result.empty() && entry.size() == result[0].size())
 21         {
 22             return;
 23         }
 24         
 25         for(size_t pos = positionToChange; pos < start.size(); ++pos)
 26         {
 27             char beforeChange = ' ';
 28             for(int i = 'a'; i <= 'z'; ++i)
 29             {
 30                                 //防止同字母替换
 31                 if(start[pos] == i)
 32                 {
 33                     continue;
 34                 }
 35                 beforeChange = start[pos];
 36                 start[pos] = i;
 37                 
 38                 //用std::find的话
 39                 /*
 40                  if(std::find(entry.begin(), entry.end(), start) != entry.end())
 41                  {
 42                       start[pos] = beforeChange;
 43                       continue;
 44                  }
 45                  */
 46                                 //如果单词已经用过的情况
 47                 if(!used_.empty() && used_.count(start)!=0 )
 48                                 {
 49                                       start[pos] = beforeChange;
 50                           continue;
 51                                 }
 52                 
 53                 
 54                 if(start == end)
 55                 {
 56                     entry.push_back(start);
 57                     
 58                                         //只需要保存最短的序列
 59                     if(!result.empty())
 60                     {
 61                         if(entry.size() < result[0].size())
 62                         {
 63                             result.clear();
 64                             result.push_back(entry);
 65                         }
 66                         else if(entry.size() == result[0].size())
 67                         {
 68                             result.push_back(entry);
 69                         }
 70                     }
 71                     else
 72                     {
 73                         result.push_back(entry);
 74                     }
 75                     //完成一个序列,把前面加入的end弹出
 76                     entry.pop_back();
 77                     return;
 78                 }
 79                 
 80                 if(dict.find(start) != dict.end())
 81                 {
 82                     entry.push_back(start);
 83                     used_.insert(start);
 84                     Find(start, end, dict, 0, result, entry);
 85                     used_.erase(*entry.rbegin());
 86                     entry.pop_back();
 87                     
 88                     
 89                     if(!entry.empty())
 90                     {
 91                         start = *entry.rbegin();
 92                     }
 93                     else
 94                     {
 95                         start[pos] = beforeChange;
 96                     }
 97                 }
 98                 else
 99                 {
100                     start[pos] = beforeChange;
101                 }
102             }
103         }
104         
105         return;
106     }
107     
108     std::unordered_set<std::string> used_;
109 };
递归实现

相关文章: