字梯(到达目标字的最短链的长度)
给定一本字典,以及两个单词“start”和“target”(长度相同)。如果存在,则查找从“开始”到“目标”的最小链的长度,使得链中的相邻单词仅相差一个字符,并且链中的每个单词都是有效单词,即它存在于字典中。可以假设“目标”词存在于字典中,并且所有字典词的长度相同。
例子:
Input: Dictionary = {POON, PLEE, SAME, POIE, PLEA, PLIE, POIN}, start = TOON, target = PLEA
Output: 7
Explanation: TOON – POON – POIN – POIE – PLIE – PLEE – PLEA
Input: Dictionary = {ABCD, EBAD, EBCD, XYZA}, start = ABCV, target = EBAD
Output: 4
Explanation: ABCV – ABCD – EBCD – EBAD
方法:解决问题的想法是使用 BFS。要找到通过 BFS 的最短路径,请从起始字开始并将其推入队列。并且一旦第一次找到目标,则返回该级别的 BFS 遍历。在 BFS 的每一步中,人们都可以得到使用这么多步骤可以形成的所有单词。因此,每当第一次找到目标单词时,这将是最短单词链的长度。
- 从给定的起始词开始。
- 推入队列中的单词
- 循环运行直到队列为空
- 遍历与其相邻(相差一个字符)的所有单词并将该单词推入队列(对于 BFS)
- 继续这样做,直到我们找到目标词或者我们已经遍历了所有词。
以下是上述想法的实现。
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)