D-BFS-DFS-LeetCode126-单词接龙 II

题目

给定两个单词(beginWord 和 endWord)和一个字典 wordList,找出所有从 beginWord 到 endWord 的最短转换序列。转换需遵循如下规则:

每次转换只能改变一个字母。
转换过程中的中间单词必须是字典中的单词。
说明:

如果不存在这样的转换序列,返回一个空列表。
所有单词具有相同的长度。
所有单词只由小写字母组成。
字典中不存在重复的单词。
你可以假设 beginWord 和 endWord 是非空的,且二者不相同。
示例 1:

输入:
beginWord = "hit",
endWord = "cog",
wordList = ["hot","dot","dog","lot","log","cog"]

输出:
[
  ["hit","hot","dot","dog","cog"],
  ["hit","hot","lot","log","cog"]
]
示例 2:

输入:
beginWord = "hit"
endWord = "cog"
wordList = ["hot","dot","dog","lot","log"]

输出: []

解释: endWord "cog" 不在字典中,所以不存在符合要求的转换序列。

思路1(超时)

递归。DFS。当前单词分叉:所有与当前单词差一个字母且没用过的单词。可能会遇到深度特别大的路径,超时。

代码1

class Solution {
    public static int minListLength=Integer.MAX_VALUE;
    public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList) {
        minListLength=wordList.size()+1;

        List<List<String>> res=new ArrayList<List<String>>();
        
		int end = wordList.indexOf(endWord);
		if(end == -1) {
			return res;
		}
        
        List<String> list=new ArrayList<String>();
        list.add(beginWord);
        
        boolean[] isUsed=new boolean[wordList.size()];
        int begin = wordList.indexOf(beginWord);
		if(begin == -1) {
			
		}else{
           isUsed[begin]=true; 
        }
        
        Map<Integer,String> positionIS=new HashMap<Integer,String>();
        for(int i=0;i<wordList.size();i++){
            positionIS.put(i,wordList.get(i));
        }
        Map<String,Integer> positionSI=new HashMap<String,Integer>();
        for(int i=0;i<wordList.size();i++){
            positionSI.put(wordList.get(i),i);
        }
        
        int[][] doubleArray=new int[wordList.size()+1][wordList.size()+1];
        for(int i=0;i<wordList.size()+1;i++){
            for(int j=i;j<wordList.size()+1;j++){
                if(i==0){
                    if(j==i){
                        doubleArray[i][j]=2;
                    }else{
                        if(doubleArray[i][j]==0){
                            if(diffOneWord(beginWord,positionIS.get(j-1))){
                                doubleArray[i][j]=1;
                                doubleArray[j][i]=1;
                            }else{
                                doubleArray[i][j]=2;
                                doubleArray[j][i]=2;
                            }
                        }
                    }
                    continue;
                }
                
                if(j==i){
                    doubleArray[i][j]=2;
                }else{
                    if(doubleArray[i][j]==0){
                        if(diffOneWord(positionIS.get(i-1),positionIS.get(j-1))){
                            doubleArray[i][j]=1;
                            doubleArray[j][i]=1;
                        }else{
                            doubleArray[i][j]=2;
                            doubleArray[j][i]=2;
                        }
                    }
                }
            }
        }

        digui(beginWord,list,endWord,wordList,isUsed,res,positionIS,positionSI,doubleArray);
        
        if(res.size()==0){
            return res;
        }
        //res 取长度最小的元素们
        int minlength=res.get(0).size();
        for(int i=1;i<res.size();i++){
            if(res.get(i).size()<minlength){
                minlength=res.get(i).size();
            }
        }

        for(int i=0;i<res.size();i++){
            if(res.get(i).size()!=minlength){
                res.remove(i);
                i--;
            }
        }        
        return res;
    }
    public void digui(String word,List<String> list,String endWord, List<String> wordList,boolean[] isUsed,List<List<String>> res,Map<Integer,String> positionIS,Map<String,Integer> positionSI,int[][] doubleArray){
        if(list.size()>minListLength){
            return ;
        }
        if(word.equals(endWord)){
            minListLength=list.size();
            res.add(new ArrayList<String>(list));
            return ;
        }
        
        int usedCount=0;
        for(int i=0;i<wordList.size();i++){
            if(isUsed[i]==true){
                usedCount++;
            }else{
                break;
            }
        }
        if(usedCount==isUsed.length){
            return ;
        }
        
        for(int i=0;i<wordList.size();i++){

            if(!isUsed[i] && doubleArray[(positionSI.get(word)==null?0:positionSI.get(word)+1)][i+1]==1){
                list.add(wordList.get(i));
                isUsed[i]=true;
                digui(wordList.get(i),list,endWord,wordList,isUsed,res,positionIS,positionSI,doubleArray);
                list.remove(list.size()-1);
                isUsed[i]=false;
            }
        }
              
    }
    
    public boolean diffOneWord(String a,String b){
        int diffnum=0;
        for(int i=0;i<a.length();i++){
            if(a.charAt(i)!=b.charAt(i)){
                diffnum++;
            }
            if(diffnum==2){
                return false;
            }
        }
        if(diffnum==1){
            return true;
        }
        return false;
    }
}

思路2

先BFS遍历图,找到所有到达结尾单词的最短路径,同时记录图。最后再DFS遍历图。

BFS遍历图:queue用来BFS遍历图。队列按结点的深度依次存放待处理的结点。首先存放第一层结点,弹出,根据第一层结点找到所有第二层结点放入队列;弹出第二层某个结点,根据此结点找到所有第三层结点放入队列,以此类推。

记录图:记录图中每个结点的父节点们。记录图中结点的层数(深度)。

DFS遍历记录的图得出结果。

代码2

class Solution {
    
    
	public List<List<String>> findLadders(String beginWord, String endWord, List<String> wordList){

        List<List<String>> res=new ArrayList<List<String>>();
        
        int endIndex=wordList.indexOf(endWord);
        if(endIndex==-1){
            return res;
        }
    
        int beginIndex=wordList.indexOf(beginWord);
        //若beginWord不在wordList中,则添加至wordList末尾
        if(beginIndex==-1){
            wordList.add(beginWord);
            beginIndex=wordList.size()-1;
        }
        
        //queue用来BFS遍历图。队列按结点的深度依次存放待处理的结点。首先存放第一层结点,弹出,根据第一层结点找到所有第二层结点放入队列;弹出第二层某个结点,根据此结点找到所有第三层结点放入队列,以此类推。
        Queue<Integer> queue=new LinkedList<Integer>();
        queue.offer(beginIndex);
        
        //fatherNodes、height用来记录图
        //记录图中每个结点的父节点们
        Map<Integer,List<Integer>> fatherNodes=new HashMap<Integer,List<Integer>>();
        for(int i=0;i<wordList.size();i++){
            fatherNodes.put(i,new ArrayList<Integer>());
        }
        
        //记录图中结点的层数(深度)
        int[] height=new int[wordList.size()];
        height[beginIndex]=1;
        
        while(!queue.isEmpty()){
            int nowIndex=queue.poll();
            
            //若最短深度的路径已经记录完毕,退出循环
            //height[nowIndex]>=height[endIndex]针对多个父节点的情况
            if(height[endIndex]!=0 && height[nowIndex]>=height[endIndex]){
                break;
            }
            
            for(int i=0;i<wordList.size();i++){
                //height[i]==0未访问过的结点,height[i]=height[nowIndex]+1多个父节点的情况,且一个父节点已经访问过该结点
                if((height[i]==0 || height[i]==height[nowIndex]+1) && isDiffOneWord(wordList.get(nowIndex),wordList.get(i))){
                    if(height[i]==0){
                        queue.offer(i);
                        height[i]=height[nowIndex]+1;
                        fatherNodes.get(i).add(nowIndex);
                    }else{
                        //height[i]=height[nowIndex]+1多个父节点的情况,且一个父节点已经访问过该结点
                        fatherNodes.get(i).add(nowIndex);
                    }
                }
            }
        }
        
        if(height[endIndex]==0){
            return res;
        }else{
            List<String> list=new ArrayList<String>();
            list.add(wordList.get(endIndex));
            dfs(endIndex,list,res,wordList,fatherNodes,beginIndex);
        }
        
        return res;
         
    }
    
    public void dfs(int lastIndex,List<String> list,List<List<String>> res,List<String> wordList,Map<Integer,List<Integer>> fatherNodes,int beginIndex){
        if(lastIndex==beginIndex){
            List<String> newList=new ArrayList<String>(list);
            Collections.reverse(newList);
            res.add(newList);
            return ;
        }
        for(int i=0;i<fatherNodes.get(lastIndex).size();i++){
            int fatherIndex=fatherNodes.get(lastIndex).get(i);
            list.add(wordList.get(fatherIndex));
            dfs(fatherIndex,list,res,wordList,fatherNodes,beginIndex);
            list.remove(list.size()-1);
        }
    }

 
    public boolean isDiffOneWord(String a,String b){
        int diffnum=0;
        for(int i=0;i<a.length();i++){
            if(a.charAt(i)!=b.charAt(i)){
                diffnum++;
            }
            if(diffnum==2){
                return false;
            }
        }
        if(diffnum==1){
            return true;
        }
        return false;
    }


}

总结

1.队列可用来BFS遍历图。

2.记录图可以记录每个结点的父结点和层数。

3.递归用来DFS遍历图。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值