「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。
题目描述
这是leetcode上的一道题目,首先应该要做的是将问题抽象出一个模型出来。在这个问题上我们可以将问题抽象为从hit开始通过一条路径最终到达cog,于是自然就想到"hit"应该抽象成一个点,而每两个不同单词之间就会有距离,这一点类似于海明距离。于是问题就抽象为搜索问题,问题的解决方法有两种:dfs和bfs
题解
dfs
数据结构:图(二维数组)。
算法:DFS
对于wordList中的每个元素都可以看成一个点,点与点之间如果只差一个字符那么就可以形成一条边,图建好后就可以用dfs搜索了。
注:由于该题只需要一个解,那么在回溯的时候visited不需要回溯,因为已经访问过该点,改点后面的结果之前已经知道了,如果通过该点已有答案,那么程序早已结束(因为只需要一个答案)。
如图,如果通过A点将D点以后的元素都访问完后不进行回溯,那么将省去B,C的无效访问。
但是如果要所有的答案的话,那么就要回溯了,因为D之前的路径是不同的。
由此可以知道,不能盲目套模板,要根据具体题目具体分析。
class Solution {
boolean getDistance(String s1,String s2){
int len1=s1.length();
int len2=s2.length();
int num=0;
if(Math.abs(len1-len2)!=0)return false;
for(int i=0; i<len1; i++){
if(s1.charAt(i)!=s2.charAt(i))num++;
if(num>1)return false;
}
if(num!=1)return false;
return true;
}
List<String> ans=new ArrayList<>();
ArrayList<String> words;
int len;
public List<String> findLadders(String beginWord, String endWord, List<String> wordList) {
words=new ArrayList<>();
words.add(beginWord);
words.addAll(wordList);
int len=words.size();
this.len=len;
boolean[][] g=new boolean[len][len];
visited=new boolean[len];
for(int i=0; i<len; i++){
for(int j=i+1; j<len; j++){
if(getDistance(words.get(i),words.get(j))){
g[i][j]=true;
g[j][i]=true;
}
}
}
visited[0]=true;
ans.add(words.get(0));
DFS(0,endWord,g);
if(!ans.get(ans.size()-1).equals(endWord))return new ArrayList<>();
return ans;
}
boolean[] visited;
boolean flag=false;
private void DFS(int pos, String endWord,boolean[][] g) {
if(flag)return;
if(endWord.equals(words.get(pos))){
flag=true;
return;
}
for(int i=0; i<len; i++){
if(g[pos][i]&&!visited[i]){
visited[i]=true;
ans.add(words.get(i));
DFS(i,endWord,g);
if(flag)return;
ans.remove(ans.size()-1);
// visited[i]=false;
}
}
}
}
bfs
数据结构:队列
算法:记忆化+BFS
说实话,这道题一开始是想用BFS做的,但是普通BFS的缺陷是不能得到路径,只能知道能不能到最终点,于是需要对BFS队列中的节点做一些改造,可以在节点中记录该节点前一个节点是哪个,这样的话就可以在得到终点后回溯回去,就可以得到路径了。
同样的,BFS中每个节点也只需要访问一次。
class Solution {
boolean getDistance(String s1,String s2){
int len1=s1.length();
int len2=s2.length();
int num=0;
if(Math.abs(len1-len2)!=0)return false;
for(int i=0; i<len1; i++){
if(s1.charAt(i)!=s2.charAt(i))num++;
if(num>1)return false;
}
if(num!=1)return false;
return true;
}
List<String> ans=new ArrayList<>();
ArrayList<String> words;
int len;
public List<String> findLadders(String beginWord, String endWord, List<String> wordList) {
words=new ArrayList<>();
words.add(beginWord);
words.addAll(wordList);
int len=words.size();
this.len=len;
boolean[][] g=new boolean[len][len];
visited=new boolean[len];
for(int i=0; i<len; i++){
for(int j=i+1; j<len; j++){
if(getDistance(words.get(i),words.get(j))){
g[i][j]=true;
g[j][i]=true;
}
}
}
BFS(endWord,g);
if(ans.size()==0||!ans.get(ans.size()-1).equals(endWord))return new ArrayList<>();
return ans;
}
private void BFS(String endWord,boolean[][] g) {
Queue<Integer> queue=new LinkedList<>();
visited[0]=true;
HashMap<Integer,Integer> tmp=new HashMap<>();
queue.offer(0);
int end=0;
while (!queue.isEmpty()){
Integer pos=queue.poll();
if(words.get(pos).equals(endWord)){
end=pos;
break;
}
for(int i=0; i<len; i++){
if(g[pos][i]&&!visited[i]){
visited[i]=true;
tmp.put(i,pos);
queue.offer(i);
}
}
}
ArrayList<Integer> x=new ArrayList<>();
while (end!=0){
x.add(end);
end=tmp.get(end);
}
x.add(0);
for (int i = x.size() - 1; i >= 0; i--) {
ans.add(words.get(x.get(i)));
}
}
boolean[] visited;
}