单词接龙的个人心得

目录

问题描述

问题分析

问题求解-建图+Dijkstra算法

建图

Dijkstra求单源最短路径

方法调用并求解

复杂度分析

时间复杂度

空间复杂度

总结


问题描述

题目链接:单词接龙

字典 wordList 中从单词 beginWord 和 endWord 的 转换序列 是一个按下述规格形成的序列 beginWord -> s1 -> s2 -> ... -> sk

  • 每一对相邻的单词只差一个字母。
  •  对于 1 <= i <= k 时,每个 si 都在 wordList 中。注意, beginWord 不需要在 wordList 中。
  • sk == endWord

给你两个单词 beginWord 和 endWord 和一个字典 wordList ,返回 从 beginWord 到 endWord 的 最短转换序列 中的 单词数目 。如果不存在这样的转换序列,返回 0 。

 问题分析

这道题的力扣官方题解中给出了两个方法,一个是广度优先遍历搜索结合优化建图的方法,另一个是双向广度优先遍历搜索,这两种方法此处不再赘述。首先这道题乍一看,对于图论不是很熟悉的人来说是比较难往这方面想的,我一开始想的是动态规划去求解,因为感觉有点像编辑距离,但是并没有很好的思路继续下去,因此想到了根据单词之间的关系进行构图并继续求解的方式。 

构建图的思想在我们所看到的诸多方法中是必要的一步,但是在接下来的求解的算法中,我没有使用广度优先遍历搜索,而是剑走偏锋地想到了Dijkstra算法。是的,就是那个求单源最短路径的算法,想到它的理由也很简单,因为目的是求构建出来的图其中的两个顶点的最短路径,源点就是beginWord代表的节点,目标节点是endWord代表的节点,因此我只需要在求解单源最短路径算法中加入判断条件就可以得到最终的结果。

问题求解-建图+Dijkstra算法

建图

题目给出beginWord和wordList,那么我们构建图的大小应该是单词列表长度加1,也就是将beginWord也加入到图中,方便我们求解单源最短路径。我们构建图的规则是判断两个单词之间是否只有一个字符不同,如果是那么这两个单词所对应的节点就有一条边相连,反之则没有,那么我们根据这个规则进行图的构建,详细代码如下所示:

    public int[][] getAdjacentMatrix(String beginWord,List<String> wordList){
        int[][] adj = new int[1 + wordList.size()][1 + wordList.size()];
        for(int i=0;i<adj.length;i++){
            Arrays.fill(adj[i],Integer.MAX_VALUE/2);
        }//先将所有位置置为Integer.MAX_VALUE/2.
        for(int i=0;i< wordList.size();i++){
            if(isDiffOne(beginWord,wordList.get(i))){
                adj[0][i+1]=1;
                adj[i+1][0]=1;
            }
        }//beginWord和列表中的单词关系单独处理。
        for(int i=0;i<wordList.size();i++){
            for(int j=i+1;j<wordList.size();j++){
                if(isDiffOne(wordList.get(i),wordList.get(j))){
                    adj[i+1][j+1]=1;
                    adj[j+1][i+1]=1;
                }
            }
        }//此处用于处理列表中单词的关系,注意下标要右移一位,因为下标为0的位置被beginWord占用。
        return adj;
    }
    public boolean isDiffOne(String firstWord,String secondWord){
        int m=firstWord.length();
        int count=0;
        for(int i=0;i<m;i++){
            if(firstWord.charAt(i)!=secondWord.charAt(i))
                count++;
        }
        return count == 1;
    }

 Dijkstra求单源最短路径

刚才我们根据我们设计的规则完成了题目中所给的beginWord和单词列表对应的图的构建,接下来我们将设计一个对应于题目要求的求解单源最短路径的算法,以便我们在主方法中调用它求解最终结果。

在代码实现方面,对于两两节点不能到达的情况,它们的邻接矩阵所对应的位置设置为Integer.MAX_VALUE/2,由于Dijkstra算法每次外层遍历都会确定一个节点的单源最短路径,因此当我们遍历到能够确定目标节点的最短路径时候,就可以返回当前的最短路径了,程序即可退出。具体的实现代码如下所示:

    public int dijkstra(int[][] adj,int source,int target){
        int n=adj.length;
        int[] shortest = new int[n];
        Arrays.fill(shortest,Integer.MAX_VALUE/2);
        shortest[source]=0;
        boolean[] visited = new boolean[n];
        for(int i=0;i<n;i++){
            int k=-1;
            for(int j=0;j<n;j++){
                if(!visited[j]&&(k==-1||shortest[j]<shortest[k]))
                    k=j;
            }
            visited[k]=true;
            if(k==target)
                return shortest[k];//只需要在此处加入判断条件即可。
            for(int m=0;m<n;m++){
                if(shortest[k]+adj[k][m]<shortest[m])
                    shortest[m]=shortest[k]+adj[k][m];
            }
        }
        return 0;
    }

方法调用并求解

刚才我们完成了建图和对应于该问题的Dijkstra算法的代码设计,接下来我们将完成主方法的编写以完成最终的功能。首先,我们可以判断一下endWord是否在wordList中,如果不在程序可以直接返回0,反之,我们再来编写接下来的逻辑。然后,我们需要根据beginWord和wordList来调用建图的方法构造一个关于问题的图。最后,我们调用Dijkstra算法来得到最终的结果。具体的实现代码如下所示:

    public int ladderLength(String beginWord, String endWord, List<String> wordList){
        int[][] adj = getAdjacentMatrix(beginWord, wordList);
        int endIndex=-1;
        for(int i=0;i<wordList.size();i++){
            if(endWord.equals(wordList.get(i))){
                endIndex=i;
                break;
            }
        }
        if(endIndex==-1)
            return 0;
        int dijkstra = dijkstra(adj, 0, endIndex + 1);
        return (dijkstra==0||dijkstra==Integer.MAX_VALUE/2)?0:dijkstra+1;
    }//力扣主方法

复杂度分析

时间复杂度

我们构造图的方式考虑了单词之间是否只差一个字符的情况,并且需要求解列表中每两个位置的字符串的关系,因此构造图的时间复杂度为O(m\times n^2),其中m为单词长度,n为列表长度。接着便是我们的求解单源最短路径模块,其时间复杂度为O(n^2)。因此最终算法的时间复杂度为O(m\times n^2)

空间复杂度

在我们算法的实现过程中,首先我们开辟了一块内存存储图的邻接矩阵,此处的空间复杂度为O(n^2),然后在Dijsktra算法中又开辟了一块内存存储一个一维bool型数组,用于记录该点是否被遍历,此处空间复杂度为O(n^2),因此最终算法的空间复杂度为O(n^2)

总结

这是一道力扣上的困难题,求解的算法有很多,力扣上的主流求解方法都用到了广度优先遍历算法,但是本着百花齐放,百家争鸣的原则,我剑走偏锋地使用了Dijkstra算法来求解该问题,也能够得到较好的效果。写下这篇博客并不是说我的方法超越了某某算法,只是说作为另一个求解思想供大家交流一下,毕竟一千个观众就有一千个哈姆雷特,交流产生思想碰撞的火花,那么我想创新也寓于其中吧。最后如果有什么问题,希望大家批评指正!!!

  • 32
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值