题目描述
字典 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
数据范围:
2 <= N <= 500
[KamaCoder] 110. 字符串接龙
自己看到题目的第一想法
只要能构建从 beginStr 到 endStr 的邻接矩阵, 就可以知道所有路劲了. 但是构建邻接矩阵成了难题.
看完代码随想录之后的想法
从 beginStr 开始, 从左往右替换 beginStr 中的每一个字符, 如果替换后的字符串 word 在 strList 中存在对应的字符串, 说明可以从 beginStr 改变一个字符到达对应的字符串. 使用一个 Map<String, Integer> 记录住到达 word 的路劲长度. 这样不停的遍历, 直到第一次遇到 word.equals(endStr) 则找到了对应的路劲.
import java.util.Scanner;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
public class Main {
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String beginStr = "";
String endStr = "";
Set<String> dicStrs = new HashSet<>();
while (scanner.hasNext()) {
int dicSize = scanner.nextInt();
scanner.nextLine();
String[] dicStrArrays = scanner.nextLine().split(" ");
beginStr = dicStrArrays[0];
endStr = dicStrArrays[1];
for (int i = 0; i < dicSize; i++) {
dicStrs.add(scanner.nextLine());
}
}
Map<String, Integer> wordPath = new HashMap<>();
Deque<String> words = new LinkedList<>();
String word;
words.addLast(beginStr);
wordPath.put(beginStr, 1);
while(!words.isEmpty()) {
String currentWord = words.pop();
StringBuilder wordBuilder = null;
for (int i = 0; i < currentWord.length(); i++) {
wordBuilder = new StringBuilder(currentWord);
for (int j = 0; j < 26; j++) {
wordBuilder.setCharAt(i, (char)(j + 'a'));
word = wordBuilder.toString();
if (wordPath.containsKey(word)) {
continue;
}
if (word.equals(endStr)) {
System.out.println(wordPath.get(currentWord) + 1);
return;
}
if (!dicStrs.contains(word)) {
continue;
}
wordPath.put(word, wordPath.get(currentWord) + 1);
words.addLast(word);
}
}
}
System.out.println(0);
}
}
自己实现过程中遇到哪些困难
整体不难, 一周半过后还完全可以靠逻辑快速 AC.
[KamaCoder] 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 <= N <= 100;
1 <= K <= 2000。
[KamaCoder] 105. 有向图的完全可达性
自己看到题目的第一想法
无.
看完代码随想录之后的想法
利用 dfs 不停的往前遍历, 同时因为是双向图, 对于遍历过的节点需要记录一下, 避免死循环.
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
// 邻接表 dfs
public class Main {
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int nodeCount = 0;
Map<Integer, List<Integer>> nodes = new HashMap<>();
while (scanner.hasNext()) {
nodeCount = scanner.nextInt();
int sideCount = scanner.nextInt();
for (int i = 0; i < sideCount; i++) {
int node = scanner.nextInt();
List<Integer> toNodes = nodes.get(node);
if (toNodes == null) {
toNodes = new ArrayList<>();
nodes.put(node, toNodes);
}
toNodes.add(scanner.nextInt());
}
}
boolean[] visited = new boolean[nodeCount + 1];
visited[0] = true;
dfs(nodes, 1, visited);
for (int i = 1; i < visited.length; i++) {
if (!visited[i]) {
System.out.println(-1);
return;
}
}
System.out.println(1);
}
private static void dfs(Map<Integer, List<Integer>> nodes, int node, boolean[] visited) {
if (visited[node]) {
return;
}
visited[node] = true;
List<Integer> toNodes = nodes.get(node);
if (toNodes == null) {
return;
}
for (Integer newNode : toNodes) {
dfs(nodes, newNode, visited);
}
}
}
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
// 邻接矩阵 dfs
public class Main {
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[][] nodes = null;
while (scanner.hasNext()) {
int nodeCount = scanner.nextInt();
int sideCount = scanner.nextInt();
nodes = new int[nodeCount + 1][nodeCount + 1];
for (int i = 0; i < sideCount; i++) {
nodes[scanner.nextInt()][scanner.nextInt()] = 1;
}
}
boolean[] visited = new boolean[nodes.length];
visited[0] = true;
dfs(nodes, 1, visited);
for (int i = 1; i < visited.length; i++) {
if (!visited[i]) {
System.out.println(-1);
return;
}
}
System.out.println(1);
}
private static void dfs(int[][] nodes, int node, boolean[] visited) {
if (visited[node]) {
return;
}
visited[node] = true;
for (int i = 1; i < nodes[node].length; i++) {
if (nodes[node][i] == 1) {
dfs(nodes, i, visited);
}
}
}
}
import java.util.ArrayList;
import java.util.Scanner;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
// 邻接表 bfs
public class Main {
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int nodeCount = 0;
Map<Integer, List<Integer>> nodes = new HashMap<>();
while (scanner.hasNext()) {
nodeCount = scanner.nextInt();
int sideCount = scanner.nextInt();
for (int i = 0; i < sideCount; i++) {
int node = scanner.nextInt();
List<Integer> toNodes = nodes.get(node);
if (toNodes == null) {
toNodes = new ArrayList<>();
nodes.put(node, toNodes);
}
toNodes.add(scanner.nextInt());
}
}
boolean[] visited = new boolean[nodeCount + 1];
visited[0] = true;
bfs(nodes, 1, visited);
for (int i = 1; i < visited.length; i++) {
if (!visited[i]) {
System.out.println(-1);
return;
}
}
System.out.println(1);
}
private static void bfs(Map<Integer, List<Integer>> nodes, int node, boolean[] visited) {
Deque<Integer> fromNodes = new LinkedList<>();
fromNodes.add(node);
visited[node] = true;
while (!fromNodes.isEmpty()) {
int fromNode = fromNodes.pop();
List<Integer> toNodes = nodes.get(fromNode);
if (toNodes == null) {
continue;
}
for (Integer newNode : toNodes) {
if (visited[newNode]) {
continue;
}
fromNodes.add(newNode);
visited[newNode] = true;
}
}
}
}
自己实现过程中遇到哪些困难
无
题目描述
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。
你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。
输入描述
第一行包含两个整数 N, M,表示矩阵的行数和列数。之后 N 行,每行包含 M 个数字,数字为 1 或者 0,表示岛屿的单元格。
输出描述
输出一个整数,表示岛屿的周长。
输入示例
5 5 0 0 0 0 0 0 1 0 1 0 0 1 1 1 0 0 1 1 1 0 0 0 0 0 0
输出示例
14
数据范围:
1 <= M, N <= 50。
[KamaCoder] 106. 岛屿的周长
自己看到题目的第一想法
当前陆地的上下左右方向, 每个方向有一个海水, 则周长+1;
看完代码随想录之后的想法
方法1是一样的想法. 方法2通过计算陆地个数, 用陆地个数*4-相邻陆地个数*2计算.
import java.util.Scanner;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
public class Main {
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[][] nodes = null;
boolean[][] visited = null;
while (scanner.hasNext()) {
nodes = new int[scanner.nextInt()][scanner.nextInt()];
visited = new boolean[nodes.length][nodes[0].length];
for (int i = 0; i < nodes.length; i++) {
for (int j = 0; j < nodes[i].length; j++) {
nodes[i][j] = scanner.nextInt();
}
}
}
for (int i = 0; i < nodes.length; i++) {
for (int j = 0; j < nodes[i].length; j++) {
if (nodes[i][j] != 1) {
continue;
}
System.out.println(dfs(nodes, visited, i, j));
return;
}
}
System.out.println(0);
}
private static int dfs(int[][] nodes, boolean[][] visited, int x, int y) {
if (visited[x][y]) {
return 0;
}
visited[x][y] = true;
int newX;
int newY;
int perimeter = 0;
for (int i = 0; i < dir.length; i++) {
newX = x + dir[i][0];
newY = y + dir[i][1];
if (newX < 0 || newX >= nodes.length || newY < 0 || newY >= nodes[newX].length) {
perimeter++;
continue;
}
if (nodes[newX][newY] == 0) {
perimeter++;
} else {
perimeter += dfs(nodes, visited, newX, newY);
}
}
return perimeter;
}
}
import java.util.Scanner;
import java.util.Deque;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
// 巧妙记边法
public class Main {
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int[][] nodes = null;
boolean[][] visited = null;
while (scanner.hasNext()) {
nodes = new int[scanner.nextInt()][scanner.nextInt()];
visited = new boolean[nodes.length][nodes[0].length];
for (int i = 0; i < nodes.length; i++) {
for (int j = 0; j < nodes[i].length; j++) {
nodes[i][j] = scanner.nextInt();
}
}
}
int count = 0;
int duplicate = 0;
for (int i = 0; i < nodes.length; i++) {
for (int j = 0; j < nodes[i].length; j++) {
if (nodes[i][j] != 1) {
continue;
}
count++;
int newX;
int newY;
for (int k = 0; k < 2; k++) {
newX = i + dir[k][0];
newY = j + dir[k][1];
if (newX >= nodes.length || newY >= nodes[newX].length) {
continue;
}
if (nodes[newX][newY] == 1) {
duplicate++;
}
}
}
}
System.out.println(count * 4 - duplicate * 2);
}
}
自己实现过程中遇到哪些困难
每个相邻的岛屿, 边是重复计算了2次, 一开始算成一次了.