有道的一道面试题 突然觉得跟word ladder有些关系

首先,在有道面实习的时候,问到了这样的一个题目,就是说一个图像识别类似的问题,假设改图片中就是一个英语单词。该单词的长度是未知的,该单词的每一位都太模糊了,但是大概可以给几个候选。比如:原本的字母可能是a, 但是由于图像太模糊了,只能猜大概是 d,o,b 3个字母其中一个。那么最后要求输出所有的单词种类。


DFS的话。由于单词本身的长度太长的话,递归的深度可能太深了。当时我确实没想到什么好点子,今天突然做到word ladder 这道题,似乎是可以使用父节点之类的什么东西。没有想明白,如果大家有什么好的idea,可以告诉我,不胜感激。

PS:当时面试官提醒的是 DFS 加一个小trick之类的。至今还没想明白。


题目描述:

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

  1. Only one letter can be changed at a time
  2. Each intermediate word must exist in the dictionary

For example,

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

As one shortest transformation is "hit" -> "hot" -> "dot" -> "dog" -> "cog",
return its length 5.


要求最短的路径,BFS当然是首选。直接可以得到最短路径。因此代码如下:

const char alphabet[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
class Solution {
public:
    int ladderLength(string start, string end, unordered_set
   
   
    
     &dict) {

    if(dict.size()  == 0  || start ==  end)
    {
        return 0;
    }
    int curStep = 1;
    int minStep = INT_MAX;
    unordered_set
    
    
     
      visited;

    queue
     
     
      
       prev;
    queue
      
      
       
        next;
    prev.push(start);

    int n = start.size();
    string curWord;
    string temp;
    while(!prev.empty())
    {
        curStep += 1;
        while(!prev.empty())
        {
            temp = prev.front();
            //cout << curStep << " " << temp << endl;
            prev.pop();
            for(int i = 0 ; i < n; ++i)
            {
                curWord = temp;
                for(int j = 0 ; j < 26; ++j )
                {
                    if(curWord[i] == alphabet[j])
                    {
                        continue;
                    }
                    curWord[i] = alphabet[j];
                    //cout << curWord << endl;
                    if(curWord == end)
                    {
                        return curStep;
                    }
                    if(dict.find(curWord) != dict.end() && visited.find(curWord) == visited.end())
                    {
                        //cout << "xq" << endl;
                        visited.insert(curWord);
                        next.push(curWord);
                    }
                    curWord = temp; //!!!!!
                }
            }
        }
        swap(prev, next);
    }
    return 0;
}
};

      
      
     
     
    
    
   
   

对于上述代码,值得一提的是,每次在访问了当前单词之后,必须恢复原来的单词。


word ladder 2, 跟上面的题目一致,不再是输出长度,而是得到所有可能的路径,这里有个小窍门:

如果要输出所有的路径,如果对已经走过的路径进行保存的话,空间是会非常大的,因为每一个节点再最坏情况下有26个后继节点,由于这其实是一个树状的结构。我们可以通过保存每一个节点的父亲节点(唯一的),即可节省空间。

因此,代码如下:

class Solution {
private:

void buildPath( unordered_map
   
   
    
     > & parent, const string start, vector
    
    
     
     
      
       > &ret,
               vector
      
      
       
        &curPath, const string word)
{
   // cout << "build path..." << endl;
    curPath.push_back(word);
    if(word == start)
    {
        ret.push_back(curPath);
        reverse(ret.back().begin(), ret.back().end());
    }
    else
    {

        for(int i = 0 ; i < parent[word].size() ; ++i)
        {
            buildPath( parent, start,ret, curPath, parent[word][i]);
        }
        
    }
    curPath.pop_back();
}

public:

vector< vector< string> > findLadders( string start, string end, unordered_set
       
       
         & dict) { vector 
         
         
           > ret; //必须不包含重复的元素??? unordered_set 
          
            cur, next; cur.insert(start); unordered_set 
           
             visited; unordered_map 
            
              > parent; bool found = false; string curWord, tempWord; while(!cur.empty() && !found) { //cout << "xq" << endl; found = false; //将该层的所有节点入栈 for(auto it = cur.begin(); it != cur.end() ; ++it) visited.insert(*it); for(auto it = cur.begin() ; it != cur.end() ; ++it) { curWord = *it; for(int i = 0 ; i < curWord.size() ; ++i) { tempWord = curWord; for(char c = 'a' ; c <= 'z' ; ++c) { if(tempWord[i] == c) continue; tempWord[i] = c; if(tempWord == end) { found = true; //在这一层找到了该节点,下面的层就不用管了,但是当前层的单词得考虑完毕。所以不用break } if ( visited.count(tempWord) == 0 && ( dict.count(tempWord) > 0 || tempWord == end )) { parent[tempWord].push_back(curWord); next.insert(tempWord); } tempWord = curWord; } } } cur.clear(); swap(cur, next); } if(found) { vector 
             
               curPath; //为了下面的函数的递归调用 buildPath(parent, start, ret, curPath, end); } return ret; } }; 
              
             
            
           
          
         
       
      
      
     
     
    
    
   
   



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值