📜  字梯(到达目标字的最短链的长度)

📅  最后修改于: 2022-05-13 01:57:53.918000             🧑  作者: Mango

字梯(到达目标字的最短链的长度)

给定一本字典,以及两个单词“start”和“target”(长度相同)。如果存在,则查找从“开始”到“目标”的最小链的长度,使得链中的相邻单词仅相差一个字符,并且链中的每个单词都是有效单词,即它存在于字典中。可以假设“目标”词存在于字典中,并且所有字典词的长度相同。

例子:

方法:解决问题的想法是使用 BFS。要找到通过 BFS 的最短路径,请从起始字开始并将其推入队列。并且一旦第一次找到目标,则返回该级别的 BFS 遍历。在 BFS 的每一步中,人们都可以得到使用这么多步骤可以形成的所有单词。因此,每当第一次找到目标单词时,这将是最短单词链的长度。

  1. 从给定的起始词开始。
  2. 推入队列中的单词
  3. 循环运行直到队列为空
  4. 遍历与其相邻(相差一个字符)的所有单词并将该单词推入队列(对于 BFS)
  5. 继续这样做,直到我们找到目标词或者我们已经遍历了所有词。

以下是上述想法的实现。

C++
// C++ program to find length
// of the shortest chain
// transformation from source
// to target
#include 
using namespace std;
 
// Returns length of shortest chain
// to reach 'target' from 'start'
// using minimum number of adjacent
// moves.  D is dictionary
int shortestChainLen(
string start, string target,
set& D)
{
   
    if(start == target)
      return 0;
 
    // If the target string is not
    // present in the dictionary
    if (D.find(target) == D.end())
        return 0;
 
    // To store the current chain length
    // and the length of the words
    int level = 0, wordlength = start.size();
 
    // Push the starting word into the queue
    queue Q;
    Q.push(start);
 
    // While the queue is non-empty
    while (!Q.empty()) {
 
        // Increment the chain length
        ++level;
 
        // Current size of the queue
        int sizeofQ = Q.size();
 
        // Since the queue is being updated while
        // it is being traversed so only the
        // elements which were already present
        // in the queue before the start of this
        // loop will be traversed for now
        for (int i = 0; i < sizeofQ; ++i) {
 
            // Remove the first word from the queue
            string word = Q.front();
            Q.pop();
 
            // For every character of the word
            for (int pos = 0; pos < wordlength; ++pos) {
 
                // Retain the original character
                // at the current position
                char orig_char = word[pos];
 
                // Replace the current character with
                // every possible lowercase alphabet
                for (char c = 'a'; c <= 'z'; ++c) {
                    word[pos] = c;
 
                    // If the new word is equal
                    // to the target word
                    if (word == target)
                        return level + 1;
 
                    // Remove the word from the set
                    // if it is found in it
                    if (D.find(word) == D.end())
                        continue;
                    D.erase(word);
 
                    // And push the newly generated word
                    // which will be a part of the chain
                    Q.push(word);
                }
 
                // Restore the original character
                // at the current position
                word[pos] = orig_char;
            }
        }
    }
 
    return 0;
}
 
// Driver program
int main()
{
    // make dictionary
    set D;
    D.insert("poon");
    D.insert("plee");
    D.insert("same");
    D.insert("poie");
    D.insert("plie");
    D.insert("poin");
    D.insert("plea");
    string start = "toon";
    string target = "plea";
    cout << "Length of shortest chain is: "
         << shortestChainLen(start, target, D);
    return 0;
}


Java
// Java program to find length
// of the shortest chain
// transformation from source
// to target
import java.util.*;
 
class GFG
{
 
// Returns length of shortest chain
// to reach 'target' from 'start'
// using minimum number of adjacent moves.
// D is dictionary
static int shortestChainLen(String start,
                            String target,
                            Set D)
{
 
     if(start == target)
      return 0;
    // If the target String is not
    // present in the dictionary
    if (!D.contains(target))
        return 0;
 
    // To store the current chain length
    // and the length of the words
    int level = 0, wordlength = start.length();
 
    // Push the starting word into the queue
    Queue Q = new LinkedList<>();
    Q.add(start);
 
    // While the queue is non-empty
    while (!Q.isEmpty())
    {
 
        // Increment the chain length
        ++level;
 
        // Current size of the queue
        int sizeofQ = Q.size();
 
        // Since the queue is being updated while
        // it is being traversed so only the
        // elements which were already present
        // in the queue before the start of this
        // loop will be traversed for now
        for (int i = 0; i < sizeofQ; ++i)
        {
 
            // Remove the first word from the queue
            char []word = Q.peek().toCharArray();
            Q.remove();
 
            // For every character of the word
            for (int pos = 0; pos < wordlength; ++pos)
            {
 
                // Retain the original character
                // at the current position
                char orig_char = word[pos];
 
                // Replace the current character with
                // every possible lowercase alphabet
                for (char c = 'a'; c <= 'z'; ++c)
                {
                    word[pos] = c;
 
                    // If the new word is equal
                    // to the target word
                    if (String.valueOf(word).equals(target))
                        return level + 1;
 
                    // Remove the word from the set
                    // if it is found in it
                    if (!D.contains(String.valueOf(word)))
                        continue;
                    D.remove(String.valueOf(word));
 
                    // And push the newly generated word
                    // which will be a part of the chain
                    Q.add(String.valueOf(word));
                }
 
                // Restore the original character
                // at the current position
                word[pos] = orig_char;
            }
        }
    }
 
    return 0;
}
 
// Driver code
public static void main(String[] args)
{
    // make dictionary
    Set D = new HashSet();
    D.add("poon");
    D.add("plee");
    D.add("same");
    D.add("poie");
    D.add("plie");
    D.add("poin");
    D.add("plea");
    String start = "toon";
    String target = "plea";
    System.out.print("Length of shortest chain is: "
        + shortestChainLen(start, target, D));
}
}
 
// This code is contributed by PrinciRaj1992


Python3
# Python3 program to find length of the
# shortest chain transformation from source
# to target
from collections import deque
 
# Returns length of shortest chain
# to reach 'target' from 'start'
# using minimum number of adjacent
# moves. D is dictionary
def shortestChainLen(start, target, D):
     
    if start == target:
      return 0
    # If the target is not
    # present in the dictionary
    if target not in D:
        return 0
 
    # To store the current chain length
    # and the length of the words
    level, wordlength = 0, len(start)
 
    # Push the starting word into the queue
    Q =  deque()
    Q.append(start)
 
    # While the queue is non-empty
    while (len(Q) > 0):
         
        # Increment the chain length
        level += 1
 
        # Current size of the queue
        sizeofQ = len(Q)
 
        # Since the queue is being updated while
        # it is being traversed so only the
        # elements which were already present
        # in the queue before the start of this
        # loop will be traversed for now
        for i in range(sizeofQ):
 
            # Remove the first word from the queue
            word = [j for j in Q.popleft()]
            #Q.pop()
 
            # For every character of the word
            for pos in range(wordlength):
                 
                # Retain the original character
                # at the current position
                orig_char = word[pos]
 
                # Replace the current character with
                # every possible lowercase alphabet
                for c in range(ord('a'), ord('z')+1):
                    word[pos] = chr(c)
 
                    # If the new word is equal
                    # to the target word
                    if ("".join(word) == target):
                        return level + 1
 
                    # Remove the word from the set
                    # if it is found in it
                    if ("".join(word) not in D):
                        continue
                         
                    del D["".join(word)]
 
                    # And push the newly generated word
                    # which will be a part of the chain
                    Q.append("".join(word))
 
                # Restore the original character
                # at the current position
                word[pos] = orig_char
 
    return 0
 
# Driver code
if __name__ == '__main__':
     
    # Make dictionary
    D = {}
    D["poon"] = 1
    D["plee"] = 1
    D["same"] = 1
    D["poie"] = 1
    D["plie"] = 1
    D["poin"] = 1
    D["plea"] = 1
    start = "toon"
    target = "plea"
     
    print("Length of shortest chain is: ",
    shortestChainLen(start, target, D))
 
# This code is contributed by mohit kumar 29


C#
// C# program to find length of the shortest chain
// transformation from source to target
using System;
using System.Collections.Generic;
 
class GFG
{
 
// Returns length of shortest chain
// to reach 'target' from 'start'
// using minimum number of adjacent moves.
// D is dictionary
static int shortestChainLen(String start,
                            String target,
                            HashSet D)
{
 
     if(start == target)
       return 0;
    // If the target String is not
    // present in the dictionary
    if (!D.Contains(target))
        return 0;
 
    // To store the current chain length
    // and the length of the words
    int level = 0, wordlength = start.Length;
 
    // Push the starting word into the queue
    List Q = new List();
    Q.Add(start);
 
    // While the queue is non-empty
    while (Q.Count != 0)
    {
 
        // Increment the chain length
        ++level;
 
        // Current size of the queue
        int sizeofQ = Q.Count;
 
        // Since the queue is being updated while
        // it is being traversed so only the
        // elements which were already present
        // in the queue before the start of this
        // loop will be traversed for now
        for (int i = 0; i < sizeofQ; ++i)
        {
 
            // Remove the first word from the queue
            char []word = Q[0].ToCharArray();
            Q.RemoveAt(0);
 
            // For every character of the word
            for (int pos = 0; pos < wordlength; ++pos)
            {
 
                // Retain the original character
                // at the current position
                char orig_char = word[pos];
 
                // Replace the current character with
                // every possible lowercase alphabet
                for (char c = 'a'; c <= 'z'; ++c)
                {
                    word[pos] = c;
 
                    // If the new word is equal
                    // to the target word
                    if (String.Join("", word).Equals(target))
                        return level + 1;
 
                    // Remove the word from the set
                    // if it is found in it
                    if (!D.Contains(String.Join("", word)))
                        continue;
                    D.Remove(String.Join("", word));
 
                    // And push the newly generated word
                    // which will be a part of the chain
                    Q.Add(String.Join("", word));
                }
 
                // Restore the original character
                // at the current position
                word[pos] = orig_char;
            }
        }
    }
    return 0;
}
 
// Driver code
public static void Main(String[] args)
{
    // make dictionary
    HashSet D = new HashSet();
    D.Add("poon");
    D.Add("plee");
    D.Add("same");
    D.Add("poie");
    D.Add("plie");
    D.Add("poin");
    D.Add("plea");
    String start = "toon";
    String target = "plea";
    Console.Write("Length of shortest chain is: "
        + shortestChainLen(start, target, D));
}
}
 
// This code is contributed by PrinciRaj1992


Javascript


C++
// C++ program to find length
// of the shortest chain
// transformation from source
// to target
#include 
using namespace std;
 
// Returns length of shortest chain
// to reach 'target' from 'start'
// using minimum number of adjacent
// moves.  D is dictionary
int shortestChainLen(
string start, string target,
set& D)
{
   
   if(start == target)
      return 0;
   
  // Map of intermediate words and
  // the list of original words
  map> umap;
 
  // Find all the intermediate
  // words for the start word
  for(int i = 0; i < start.size(); i++)
  {
    string str = start.substr(0,i) + "*" +
                        start.substr(i+1);
    umap[str].push_back(start);
  }
 
  // Find all the intermediate words for
  // the words in the given Set
  for(auto it = D.begin(); it != D.end(); it++)
  {
    string word = *it;
    for(int j = 0; j < word.size(); j++)
    {
      string str = word.substr(0,j) + "*" +
                          word.substr(j+1);
      umap[str].push_back(word);
    }
  }
 
  // Perform BFS and push (word, distance)
  queue> q;
 
  map visited;
 
  q.push(make_pair(start,1));
  visited[start] = 1;
 
  // Traverse until queue is empty
  while(!q.empty())
  {
    pair p = q.front();
    q.pop();
 
    string word = p.first;
    int dist = p.second;
 
    // If target word is found
    if(word == target)
    {
      return dist;
    }
 
    // Finding intermediate words for
    // the word in front of queue
    for(int i = 0; i < word.size(); i++)
    {
      string str = word.substr(0,i) + "*" +
                           word.substr(i+1);
 
      vector vect = umap[str];
      for(int j = 0; j < vect.size(); j++)
      {
        // If the word is not visited
        if(visited[vect[j]] == 0)
        {
          visited[vect[j]] = 1;
          q.push(make_pair(vect[j], dist + 1));
        }
      }
    }
 
  }
 
    return 0;
}
 
// Driver code
int main()
{
    // Make dictionary
    set D;
    D.insert("poon");
    D.insert("plee");
    D.insert("same");
    D.insert("poie");
    D.insert("plie");
    D.insert("poin");
    D.insert("plea");
    string start = "toon";
    string target = "plea";
    cout << "Length of shortest chain is: "
         << shortestChainLen(start, target, D);
    return 0;
}


Java
// Java program to find length
// of the shortest chain
// transformation from source
// to target
import java.util.*;
 
class GFG{
  static class pair
  {
    String first;
    int second;
    public pair(String first, int second) 
    {
      this.first = first;
      this.second = second;
    }   
  }
 
  // Returns length of shortest chain
  // to reach 'target' from 'start'
  // using minimum number of adjacent
  // moves.  D is dictionary
  static int shortestChainLen(
    String start, String target,
    HashSet D)
  {
 
    if(start == target)
      return 0;
 
    // Map of intermediate words and
    // the list of original words
    Map> umap = new HashMap<>();
 
    // Find all the intermediate
    // words for the start word
    for(int i = 0; i < start.length(); i++)
    {
      String str = start.substring(0,i) + "*" +
        start.substring(i+1);
      Vector s = umap.get(str);
      if(s==null)
        s = new Vector();
      s.add(start);
      umap.put(str, s);
    }
 
    // Find all the intermediate words for
    // the words in the given Set
    for(String it : D)
    {
      String word = it;
      for(int j = 0; j < word.length(); j++)
      {
        String str = word.substring(0, j) + "*" +
          word.substring(j + 1);
        Vector s = umap.get(str);
        if(s == null)
          s = new Vector();
        s.add(word);
        umap.put(str, s);
      }
    }
 
    // Perform BFS and push (word, distance)
    Queue q = new LinkedList<>();
 
    Map visited = new HashMap();
 
    q.add(new pair(start, 1));
    visited.put(start, 1);
 
    // Traverse until queue is empty
    while(!q.isEmpty())
    {
      pair p = q.peek();
      q.remove();
 
      String word = p.first;
      int dist = p.second;
 
      // If target word is found
      if(word == target)
      {
        return dist;
      }
 
      // Finding intermediate words for
      // the word in front of queue
      for(int i = 0; i < word.length(); i++)
      {
        String str = word.substring(0, i) + "*" +
          word.substring(i + 1);
 
        Vector vect = umap.get(str);
        for(int j = 0; j < vect.size(); j++)
        {
          // If the word is not visited
          if(!visited.containsKey(vect.get(j)) )
          {
            visited.put(vect.get(j), 1);
            q.add(new pair(vect.get(j), dist + 1));
          }
        }
      }
 
    }
 
    return 0;
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    // Make dictionary
    HashSet D = new HashSet();
    D.add("poon");
    D.add("plee");
    D.add("same");
    D.add("poie");
    D.add("plie");
    D.add("poin");
    D.add("plea");
    String start = "toon";
    String target = "plea";
    System.out.print("Length of shortest chain is: "
                     + shortestChainLen(start, target, D));
  }
}
 
// This code is contributed by 29AjayKumar


输出
Length of shortest chain is: 7

时间复杂度: O(N² * M),其中 M 是字典中最初的条目数,N 是字符串的大小。
辅助空间: O(M * N)

替代实现:(保持中间词和原词的映射):

以下是上述方法的替代实现。

在这里,在这种方法中,我们找出起始词的所有中间词和给定字典列表中的词,并维护中间词的映射和原始词的向量(map< 字符串,vector< 字符串> >)。例如,对于单词“POON”,中间词是“*OON”、“P*ON”、“PO*N”、“POO*”。然后,我们从起始词开始执行 BFS 遍历,并将一对起始词和距离 (pair(word, distance)) 推送到队列中,直到到达目标词。那么,距离就是我们的答案。

C++

// C++ program to find length
// of the shortest chain
// transformation from source
// to target
#include 
using namespace std;
 
// Returns length of shortest chain
// to reach 'target' from 'start'
// using minimum number of adjacent
// moves.  D is dictionary
int shortestChainLen(
string start, string target,
set& D)
{
   
   if(start == target)
      return 0;
   
  // Map of intermediate words and
  // the list of original words
  map> umap;
 
  // Find all the intermediate
  // words for the start word
  for(int i = 0; i < start.size(); i++)
  {
    string str = start.substr(0,i) + "*" +
                        start.substr(i+1);
    umap[str].push_back(start);
  }
 
  // Find all the intermediate words for
  // the words in the given Set
  for(auto it = D.begin(); it != D.end(); it++)
  {
    string word = *it;
    for(int j = 0; j < word.size(); j++)
    {
      string str = word.substr(0,j) + "*" +
                          word.substr(j+1);
      umap[str].push_back(word);
    }
  }
 
  // Perform BFS and push (word, distance)
  queue> q;
 
  map visited;
 
  q.push(make_pair(start,1));
  visited[start] = 1;
 
  // Traverse until queue is empty
  while(!q.empty())
  {
    pair p = q.front();
    q.pop();
 
    string word = p.first;
    int dist = p.second;
 
    // If target word is found
    if(word == target)
    {
      return dist;
    }
 
    // Finding intermediate words for
    // the word in front of queue
    for(int i = 0; i < word.size(); i++)
    {
      string str = word.substr(0,i) + "*" +
                           word.substr(i+1);
 
      vector vect = umap[str];
      for(int j = 0; j < vect.size(); j++)
      {
        // If the word is not visited
        if(visited[vect[j]] == 0)
        {
          visited[vect[j]] = 1;
          q.push(make_pair(vect[j], dist + 1));
        }
      }
    }
 
  }
 
    return 0;
}
 
// Driver code
int main()
{
    // Make dictionary
    set D;
    D.insert("poon");
    D.insert("plee");
    D.insert("same");
    D.insert("poie");
    D.insert("plie");
    D.insert("poin");
    D.insert("plea");
    string start = "toon";
    string target = "plea";
    cout << "Length of shortest chain is: "
         << shortestChainLen(start, target, D);
    return 0;
}

Java

// Java program to find length
// of the shortest chain
// transformation from source
// to target
import java.util.*;
 
class GFG{
  static class pair
  {
    String first;
    int second;
    public pair(String first, int second) 
    {
      this.first = first;
      this.second = second;
    }   
  }
 
  // Returns length of shortest chain
  // to reach 'target' from 'start'
  // using minimum number of adjacent
  // moves.  D is dictionary
  static int shortestChainLen(
    String start, String target,
    HashSet D)
  {
 
    if(start == target)
      return 0;
 
    // Map of intermediate words and
    // the list of original words
    Map> umap = new HashMap<>();
 
    // Find all the intermediate
    // words for the start word
    for(int i = 0; i < start.length(); i++)
    {
      String str = start.substring(0,i) + "*" +
        start.substring(i+1);
      Vector s = umap.get(str);
      if(s==null)
        s = new Vector();
      s.add(start);
      umap.put(str, s);
    }
 
    // Find all the intermediate words for
    // the words in the given Set
    for(String it : D)
    {
      String word = it;
      for(int j = 0; j < word.length(); j++)
      {
        String str = word.substring(0, j) + "*" +
          word.substring(j + 1);
        Vector s = umap.get(str);
        if(s == null)
          s = new Vector();
        s.add(word);
        umap.put(str, s);
      }
    }
 
    // Perform BFS and push (word, distance)
    Queue q = new LinkedList<>();
 
    Map visited = new HashMap();
 
    q.add(new pair(start, 1));
    visited.put(start, 1);
 
    // Traverse until queue is empty
    while(!q.isEmpty())
    {
      pair p = q.peek();
      q.remove();
 
      String word = p.first;
      int dist = p.second;
 
      // If target word is found
      if(word == target)
      {
        return dist;
      }
 
      // Finding intermediate words for
      // the word in front of queue
      for(int i = 0; i < word.length(); i++)
      {
        String str = word.substring(0, i) + "*" +
          word.substring(i + 1);
 
        Vector vect = umap.get(str);
        for(int j = 0; j < vect.size(); j++)
        {
          // If the word is not visited
          if(!visited.containsKey(vect.get(j)) )
          {
            visited.put(vect.get(j), 1);
            q.add(new pair(vect.get(j), dist + 1));
          }
        }
      }
 
    }
 
    return 0;
  }
 
  // Driver code
  public static void main(String[] args)
  {
 
    // Make dictionary
    HashSet D = new HashSet();
    D.add("poon");
    D.add("plee");
    D.add("same");
    D.add("poie");
    D.add("plie");
    D.add("poin");
    D.add("plea");
    String start = "toon";
    String target = "plea";
    System.out.print("Length of shortest chain is: "
                     + shortestChainLen(start, target, D));
  }
}
 
// This code is contributed by 29AjayKumar
输出
Length of shortest chain is: 7

时间复杂度: O(N² * M),其中 M 是字典中最初的条目数,N 是字符串的大小。
辅助空间: O(M * N)