字符串接龙

目录

题目描述

思路

         总结


题目描述

字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:

  1. 序列中第一个字符串是 beginStr。

  2. 序列中最后一个字符串是 endStr。

  3. 每次转换只能改变一个字符。

  4. 转换过程中的中间字符串必须是字典 strList 中的字符串。

给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。

输入描述

第一行包含一个整数 N,表示字典 strList 中的字符串数量。 第二行包含两个字符串,用空格隔开,分别代表 beginStr 和 endStr。 后续 N 行,每行一个字符串,代表 strList 中的字符串。

输出描述

输出一个整数,代表从 beginStr 转换到 endStr 需要的最短转换序列中的字符串数量。如果不存在这样的转换序列,则输出 0。

输入示例:

6
abc def
efc
dbc
ebc
dec
dfc
yhn

输出示例:

4

提示信息

从 startStr 到 endStr,在 strList 中最短的路径为 abc -> dbc -> dec -> def,所以输出结果为 4。

数据范围:

2 <= N <= 500

思路

1.方法

  题目的结果由于是需要的最短转换序列,也就是是求出最短路径,就可以了,不用找出具体路径。所以这题我们用bfs即可,广搜只要搜到了终点,那么一定是最短的路径。因为广搜就是以起点中心向四周扩散的搜索。如果用dfs,要在到达终点的不同路径中选则一条最短路比较麻烦

2.图中的线是如何连在一起的

  确定了方法后,我们需要思考题目给出的问题:

首先题目中并没有给出点与点之间的连线,而是要我们自己去连,条件是字符只能差一个。

所以判断点与点之间的关系,需要判断是不是差一个字符,如果差一个字符,那就是有链接

3.注意

  • 本题是一个无向图,需要用标记位,标记着节点是否走过,否则会陷入死循环!
  • 使用HashSet来检查字符串是否出现在字符串集合里更快一些

代码示例:

import java.util.*;

public class 字符串接龙{
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int n=scanner.nextInt();
        scanner.nextLine();
        String beginStr=scanner.next();;
        String endStr=scanner.next();
        scanner.nextLine();//读取换行符

        List wordList=new ArrayList<>();//将字符串储存到集合中
        wordList.add(beginStr);
        wordList.add(endStr);
        for (int i = 0; i < n; i++) {
            wordList.add(scanner.nextLine());//读取字符串
        }
        int ans=bfs(beginStr,endStr,wordList);
        System.out.println(ans);
    }

    static int bfs(String beginStr,String endStr,List wordlist){//bfs
        int len=1;//将长度设为一
        Set list=new HashSet<>(wordlist);//:将 wordList转换为HashSet,方便快速查找某个单词是否在单词列表中
        Set visited=new HashSet<>();//用于记录已经访问过的单词,避免重复访问。
        Queue q=new LinkedList<>();//用队列记录bfs的每一层
        visited.add(beginStr);//将开始的字符串记录
        q.add(beginStr);//将开始的字符串添加到第一层
        q.add(null);//加入 null 作为层分隔符

        while(!q.isEmpty()) {//开始bfs
            String node = q.remove(); //移除并返回队列头部元素

            if(node==null) {//检查当前层的所有节点是否都已经处理完毕。
                if (!q.isEmpty()) {//接着检查队列是否为空,不为空,说明还有下一层的节点需要处理,此时将 len 加 1,表示进入下一层,并且在队列末尾再添加一个 null 作为下一层的分隔符。
                    len++;
                    q.add(null);
                }
                continue;//使用 continue 语句跳过本次循环的后续处理,直接进入下一次循环,去处理下一个节点。
            }
            char[] charArray = node.toCharArray();
            for (int i = 0; i < charArray.length; i++) {
                char old = charArray[i];
                for (char j = 'a'; j < 'z'; j++) {
                    charArray[i] = j;
                    String newword = new String(charArray);
                    if (list.contains(newword) && !visited.contains(newword)) {
                        q.add(newword);
                        visited.add(newword);
                        if (newword.equals(endStr)) return len + 1;
                    }
                }
                charArray[i] = old;
            }
        }
/*将当前单词 node 转换为字符数组 charArray。
遍历字符数组的每个位置,将该位置的字符依次替换为 'a' 到 'z' 的字符,生成新的单词 newWord。
如果 newWord 在单词列表中且未被访问过,则将其加入队列和 visited 集合中。
如果 newWord 等于结束单词 endStr,则返回当前步数加 1。
最后将字符数组该位置的字符恢复为原来的值。*/
        return 0;

        }
    }

总结:

综合前面关于 Java 代码的分析,这道题目的核心是在给定起始单词、结束单词以及单词列表的情况下,通过广度优先搜索(BFS)算法找到从起始单词转换到结束单词的最短转换序列长度。

你可能感兴趣的:(算法)