面试题单词转换(DFS或记忆化BFS)

763 阅读2分钟

「这是我参与2022首次更文挑战的第9天,活动详情查看:2022首次更文挑战」。

题目描述

image.png 这是leetcode上的一道题目,首先应该要做的是将问题抽象出一个模型出来。在这个问题上我们可以将问题抽象为从hit开始通过一条路径最终到达cog,于是自然就想到"hit"应该抽象成一个点,而每两个不同单词之间就会有距离,这一点类似于海明距离。于是问题就抽象为搜索问题,问题的解决方法有两种:dfs和bfs

题解

dfs

数据结构:图(二维数组)。

算法:DFS

对于wordList中的每个元素都可以看成一个点,点与点之间如果只差一个字符那么就可以形成一条边,图建好后就可以用dfs搜索了。

注:由于该题只需要一个解,那么在回溯的时候visited不需要回溯,因为已经访问过该点,改点后面的结果之前已经知道了,如果通过该点已有答案,那么程序早已结束(因为只需要一个答案)。

image.png

如图,如果通过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;
}