当前位置: 首页 > news >正文

Leetcode+Java+图论II

110.字符串迁移

题目描述

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

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

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

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

4. 转换过程中的中间字符串必须是字典 strList 中的字符串,且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

原理

问题本质

这是一个单源最短路径问题,可以在无向图中建模:

  • 节点:所有单词(包括beginStr、endStr和字典中的字符串)
  • :两个单词之间恰好相差一个字符时存在边,边的权重为1
  • 目标:求从beginStr到endStr的最短路径长度

BFS核心思想

广度优先搜索(BFS)天然适合求解无权图的最短路径

  1. 分层遍历:从起始节点开始,按层逐层向外扩展
  2. 最短路径保证:第一层包含距离为1的所有节点,第二层包含距离为2的节点,以此类推
  3. 最早到达即最短:到达目标节点时,当前层数就是最短路径长度

代码

import java.util.*;public class Main {// 全局变量sum未使用,实际代码中未被调用static int sum = 0;public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();  // 读取字典中字符串的数量NString[] strings = new String[n];String start = scanner.next();  // 读取起始字符串beginStrString end = scanner.next();    // 读取结束字符串endStr// 创建包含所有单词的wordList(包括start和end)List<String> wordList = new ArrayList<>();wordList.add(start);    // 添加起始字符串wordList.add(end);      // 添加结束字符串// 读取N个字典字符串并加入wordListfor (int i = 0; i < n; i++) {strings[i] = scanner.next();wordList.add(strings[i]);}// 执行BFS计算最短路径长度int ans = bfs(start, end, wordList);System.out.print(ans);  // 输出结果}/*** BFS广度优先搜索求最短转换序列长度* @param start 起始字符串* @param end 结束字符串* @param wordList 所有可用单词列表* @return 最短序列长度,如果无法到达返回0*/public static int bfs(String start, String end, List<String> wordList) {int len = 1;  // 当前序列长度,初始为1(包含起始字符串)// set存储所有可用的单词Set<String> set = new HashSet<>(wordList);// visited记录已访问的单词,避免重复访问Set<String> visited = new HashSet<>();// 队列用于BFS,存储待处理的单词Queue<String> queue = new LinkedList<>();visited.add(start);     // 标记起始字符串已访问queue.add(start);       // 起始字符串入队queue.add(null);        // 添加null标记,用于分层统计深度while (!queue.isEmpty()) {String str = queue.remove();  // 取出队列头部元素// 遇到null标记,表示当前层结束,需要进入下一层if (str == null) {if (!queue.isEmpty()) {  // 队列非空,继续下一层len++;              // 层数加1queue.add(null);    // 添加新的null标记}continue;}// 对当前字符串的每个位置尝试替换char[] charArray = str.toCharArray();for (int i = 0; i < charArray.length; i++) {char old = charArray[i];  // 保存原始字符// 尝试将该位置替换为a-z的26个字母for (char j = 'a'; j <= 'z'; j++) {charArray[i] = j;String newWord = new String(charArray);  // 生成新单词// 检查新单词是否在字典中且未访问过if (set.contains(newWord) && !visited.contains(newWord)) {queue.add(newWord);     // 新单词入队visited.add(newWord);   // 标记为已访问// 如果到达目标字符串,返回序列长度if (newWord.equals(end)) {return len + 1;}}}charArray[i] = old;  // 恢复原始字符}}return 0;  // 无法到达目标,返回0}
}

105.有向图的完全联通

题目描述

给定一个有向图,包含 N 个节点,节点编号分别为 1,2,...,N。现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。

输入描述

第一行包含两个正整数,表示节点数量 N 和边的数量 K。 后续 K 行,每行两个正整数 s 和 t,表示从 s 节点有一条边单向连接到 t 节点。

输出描述

如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。

输入示例
4 4
1 2
2 1
1 3
2 4
输出示例
1
提示信息

从 1 号节点可以到达任意节点,输出 1。

数据范围:

1 <= N <= 100;
1 <= K <= 2000。

原理

BFS+边访问数组

DFS+邻接表

BFS+邻接表

代码

import java.util.*;public class Main {static int sum = 0;  // 未使用,冗余变量public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();  // 节点数int k = scanner.nextInt();  // 边数// 使用二维数组存储边,空间浪费严重int[][] graph = new int[k][2];for (int i = 0; i < k; i++) {graph[i][0] = scanner.nextInt();  // 起点graph[i][1] = scanner.nextInt();  // 终点}scanner.close();boolean[] visited_node = new boolean[n + 1];     // 节点访问标记boolean[][] visited_bian = new boolean[n + 1][n + 1];  // 边访问标记(冗余!)// 执行BFSif (bfs(graph, visited_node, visited_bian)) {System.out.print(1);} else {System.out.print(-1);}}/*** BFS实现(版本1):遍历所有边寻找出边,复杂度O(K)*/public static boolean bfs(int[][] graph, boolean[] visited_node, boolean[][] visited_bian) {Queue<Integer> queue = new ArrayDeque<>();  // 队列存储待访问节点queue.add(1);                               // 从1号节点开始visited_node[1] = true;                     // 标记1已访问while (!queue.isEmpty()) {int node = queue.poll();  // 取出当前节点// 遍历所有K条边,寻找以node为起点的边(O(K)复杂度!)for (int i = 0; i < graph.length; i++) {if (graph[i][0] == node) {  // 找到以node为起点的边int target = graph[i][1];// 同时检查边和节点是否访问过(逻辑冗余)if (!visited_bian[node][target] && !visited_node[target]) {visited_node[target] = true;visited_bian[node][target] = true;queue.add(target);}}}}// 检查是否所有节点都被访问for (int i = 1; i < visited_node.length; i++) {if (!visited_node[i]) return false;}return true;}
}
import java.util.*;public class Main {static int sum = 0;  // 未使用public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int k = scanner.nextInt();// 构建邻接表:adjList[i]存储i的所有出边目标List<List<Integer>> adjList = new ArrayList<>();for (int i = 0; i <= n; i++) {adjList.add(new ArrayList<>());  // 为每个节点创建空列表}for (int i = 0; i < k; i++) {int s = scanner.nextInt();int t = scanner.nextInt();adjList.get(s).add(t);  // s -> t}scanner.close();boolean[] visited_node = new boolean[n + 1];dfs(visited_node, adjList, 1);  // 从1开始DFS// 检查连通性for (int i = 1; i < visited_node.length; i++) {if (!visited_node[i]) {System.out.print(-1);return;}}System.out.print(1);}/*** DFS递归实现:深度优先遍历*/public static void dfs(boolean[] visited_node, List<List<Integer>> adjList, int cur) {visited_node[cur] = true;  // 标记当前节点List<Integer> neighbors = adjList.get(cur);  // 获取所有邻接节点if (!neighbors.isEmpty()) {for (int next : neighbors) {if (!visited_node[next]) {  // 未访问才递归dfs(visited_node, adjList, next);}}}}
}
import java.util.*;public class Main {static int sum = 0;  // 未使用public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();int k = scanner.nextInt();// 构建邻接表List<List<Integer>> adjList = new ArrayList<>();for (int i = 0; i <= n; i++) {adjList.add(new ArrayList<>());}for (int i = 0; i < k; i++) {int s = scanner.nextInt();int t = scanner.nextInt();adjList.get(s).add(t);  // s -> t}scanner.close();boolean[] visited_node = new boolean[n + 1];if (bfs(visited_node, adjList)) {System.out.print(1);} else {System.out.print(-1);}}/*** BFS实现(推荐):广度优先遍历*/public static boolean bfs(boolean[] visited_node, List<List<Integer>> adjList) {Queue<Integer> queue = new ArrayDeque<>();queue.add(1);                    // 从1开始visited_node[1] = true;          // 标记起点while (!queue.isEmpty()) {int node = queue.poll();     // 取出当前节点// 只遍历当前节点的邻接表(O(deg(node)))List<Integer> neighbors = adjList.get(node);for (int next : neighbors) {if (!visited_node[next]) {  // 未访问visited_node[next] = true;queue.add(next);}}}// 检查所有节点是否可达for (int i = 1; i < visited_node.length; i++) {if (!visited_node[i]) return false;}return true;}
}

http://www.dtcms.com/a/511809.html

相关文章:

  • git空目录处理
  • 自动化办公:用Python操作Excel、Word和PDF
  • 前端V0介绍(Vercel推出的AI前端生成工具)
  • 从 “对话” 到 “证书”:零知识证明的魔法工具箱 —— 让隐私验证走进普通人的数字生活
  • 培训类网站开发做网站需要买服务器
  • 对称树结构:原理、应用与Python实现
  • 4.4数组的基本操作
  • 湘潭网站建设优等磐石网络遨游建站
  • [go 面试] 前端请求到后端API的中间件流程解析
  • Ethernaut Level 13: Gatekeeper One - Gas计算与类型转换
  • 飞凌嵌入式ElfBoard-常用的网络服务的搭建之TFTP服务搭建
  • mybatis-plus的insertBatchSomeColumn方法实现批量插入
  • 上海传媒公司艺人seo项目优化案例分析文档
  • 【论文阅读】DiffusionDrive:截断扩散模型用于端到端自动驾驶
  • 解读Time Model Statistics中的PL/SQL 和 SQL执行时间
  • DDD(一)认识领域驱动设计(DDD的概念、主要架构模型)
  • Spring Boot集成Spring Integration全解析
  • MCP功能与架构详解
  • Spring Boot优雅关闭全解析
  • 授权登录网站怎么做网站源码怎么做
  • 网站建设遇到哪些攻击网站开发外贸客户
  • 未来之窗昭和仙君(二十六)通用押金系统开发——东方仙盟筑基期
  • 【案例】Unity 平台访问文件浏览器(汇总)
  • Matlab 曲线拟合
  • 基于CSMA-CA协议的V2X通信MATLAB仿真
  • 基于matlab实现的DnCNN网络
  • 网站一般用什么工具做wordpress英文版切换中文
  • 十大最佳摄影网站windows 版 wordpress
  • ruby 、gem 和 cocoapods的联系与区别
  • Python 圆台体积和表面积计算程序(Program for Volume and Surface area of Frustum of Cone)