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(); // 读取字典中字符串的数量N
String[] strings = new String[n];
String start = scanner.next(); // 读取起始字符串beginStr
String end = scanner.next(); // 读取结束字符串endStr
// 创建包含所有单词的wordList(包括start和end)
List<String> wordList = new ArrayList<>();
wordList.add(start); // 添加起始字符串
wordList.add(end); // 添加结束字符串
// 读取N个字典字符串并加入wordList
for (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++; // 层数加1
queue.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+邻接表
代码
java复制代码
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]; // 边访问标记(冗余!)
// 执行BFS
if (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;
}
}
java复制代码
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);
}
}
}
}
}
java复制代码
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;
}
}