103. 水流问题
题目讲解:代码随想录
重点:
- 理解从两个边界同时能够逆流而上到的点就是结果
思路:
- 初始化两个用来存储边界能到的点的数组。再用DFS探索从四个边框逆流而上能到的点
// 四个方向 private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 存储从第一边界逆流而上能到的点 boolean[][] firstBorder = new boolean[n][m]; // 存储从第二边界逆流而上能到的点 boolean[][] secondBorder = new boolean[n][m]; // 遍历最左列和最右列 for (int i = 0; i < n; i++) { dfs(graph, i, 0, firstBorder); dfs(graph, i, m - 1, secondBorder); } // 遍历最上行和最下行 for (int j = 0; j < m; j++) { dfs(graph, 0, j, firstBorder); dfs(graph, n - 1, j, secondBorder); } // DFS从边界探索, 逆流而上 private static void dfs(int[][] graph, int x, int y, boolean[][] visited) { if (visited[x][y]) return; visited[x][y] = true; for (int i = 0; i < 4; i++) { int nextX = x + dir[i][0]; int nextY = y + dir[i][1]; if (nextX < 0 || nextX >= graph.length || nextY < 0 || nextY >= graph[0].length) continue; // 从第一或第二边界, 反着逆流而上 if (graph[x][y] > graph[nextX][nextY]) continue; dfs(graph, nextX, nextY, visited); } }
- 查找两个存储边界能到的点的数组,从两个边界逆流而上都能到的点就是结果
for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (firstBorder[i][j] && secondBorder[i][j]) System.out.println(i + " " + j); } }
public class WaterFlowProblem {
// 四个方向
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
// DFS从边界探索, 逆流而上
private static void dfs(int[][] graph, int x, int y, boolean[][] visited) {
if (visited[x][y]) return;
visited[x][y] = true;
for (int i = 0; i < 4; i++) {
int nextX = x + dir[i][0];
int nextY = y + dir[i][1];
if (nextX < 0 || nextX >= graph.length || nextY < 0 || nextY >= graph[0].length) continue;
// 从第一或第二边界, 反着逆流而上
if (graph[x][y] > graph[nextX][nextY]) continue;
dfs(graph, nextX, nextY, visited);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[][] graph = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
graph[i][j] = scanner.nextInt();
}
}
// 存储从第一边界逆流而上能到的点
boolean[][] firstBorder = new boolean[n][m];
// 存储从第二边界逆流而上能到的点
boolean[][] secondBorder = new boolean[n][m];
// 遍历最左列和最右列
for (int i = 0; i < n; i++) {
dfs(graph, i, 0, firstBorder);
dfs(graph, i, m - 1, secondBorder);
}
// 遍历最上行和最下行
for (int j = 0; j < m; j++) {
dfs(graph, 0, j, firstBorder);
dfs(graph, n - 1, j, secondBorder);
}
// 从两个边界逆流而上都能到的点就是结果
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (firstBorder[i][j] && secondBorder[i][j]) {
System.out.println(i + " " + j);
}
}
}
}
}
104. 建造最大岛屿
题目讲解:代码随想录
重点:
- 理解解题思路。首先要计算各个岛屿的面积,然后再遍历图中各个0的坐标,再把这个坐标相邻的岛屿的面积统计出来,取最大即可。
思路:
- 遍历图,计算出各个岛屿的面积,并做编号记录
// 分配给当前岛屿的编号 mark = 2; boolean[][] visited = new boolean[n][m]; // 存储不同岛屿的面积 HashMap<Integer, Integer> islandSize = new HashMap<>(); // 给每个岛屿分配记号 并 计算面积 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (graph[i][j] == 0) isAllIsland = false; if (graph[i][j] == 1) { count = 0; dfs(graph, i, j, visited); islandSize.put(mark, count); mark++; } } } // DFS探索整个岛屿, 并将岛屿的所有坐标修改成编号 private static void dfs(int[][] graph, int x, int y, boolean[][] visited) { if (visited[x][y] || graph[x][y] == 0) return; visited[x][y] = true; count++; graph[x][y] = mark; for (int i = 0; i < 4; i++) { int nextX = x + dir[i][0]; int nextY = y + dir[i][1]; if (nextX < 0 || nextX >= graph.length || nextY < 0 || nextY >= graph[0].length) continue; dfs(graph, nextX, nextY, visited); } }
- 再遍历图,遍历0的坐标,并统计周边岛屿面积,将其相邻面积相加在一起。遍历所有0之后,就可以得出一个最大面积。
int result = 0; // 用来避免重复计算同一个岛屿 HashSet<Integer> set = new HashSet<>(); // 遍历图中为水域的坐标, 并将上下左右四个方向的相邻岛屿的面积相加 for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { if (graph[i][j] == 0) { set.clear(); int curSize = 1; // 遍历四个方向, 查看是否有相邻的岛屿, set用来避免重复计算同一岛屿 // 如果有相邻岛屿, 则面积相加 for (int k = 0; k < 4; k++) { int nextX = i + dir[k][0]; int nextY = j + dir[k][1]; if (nextX < 0 || nextX >= n || nextY < 0 || nextY >= m) continue; int nextMark = graph[nextX][nextY]; if (set.contains(nextMark) || !islandSize.containsKey(nextMark)) continue; set.add(nextMark); curSize += islandSize.get(nextMark); } result = Math.max(result, curSize); } } }
public class BuildLargestIsland {
// 四个方向
private static int[][] dir = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
// 分配给当前岛屿的编号
private static int mark;
// 当前岛屿的面积
private static int count;
// DFS探索整个岛屿, 并将岛屿的所有坐标修改成编号
private static void dfs(int[][] graph, int x, int y, boolean[][] visited) {
if (visited[x][y] || graph[x][y] == 0) return;
visited[x][y] = true;
count++;
graph[x][y] = mark;
for (int i = 0; i < 4; i++) {
int nextX = x + dir[i][0];
int nextY = y + dir[i][1];
if (nextX < 0 || nextX >= graph.length || nextY < 0 || nextY >= graph[0].length) continue;
dfs(graph, nextX, nextY, visited);
}
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
int m = scanner.nextInt();
int[][] graph = new int[n][m];
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
graph[i][j] = scanner.nextInt();
}
}
mark = 2;
boolean[][] visited = new boolean[n][m];
// 存储不同岛屿的面积
HashMap<Integer, Integer> islandSize = new HashMap<>();
// 整张图是否为全岛屿
boolean isAllIsland = true;
// 给每个岛屿分配记号 并 计算面积
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (graph[i][j] == 0) isAllIsland = false;
if (graph[i][j] == 1) {
count = 0;
dfs(graph, i, j, visited);
islandSize.put(mark, count);
mark++;
}
}
}
int result = 0;
if (isAllIsland) result = n * m;
// 用来避免重复计算同一个岛屿
HashSet<Integer> set = new HashSet<>();
// 遍历图中为水域的坐标, 并将上下左右四个方向的相邻岛屿的面积相加
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (graph[i][j] == 0) {
set.clear();
int curSize = 1;
// 遍历四个方向, 查看是否有相邻的岛屿, set用来避免重复计算同一岛屿
// 如果有相邻岛屿, 则面积相加
for (int k = 0; k < 4; k++) {
int nextX = i + dir[k][0];
int nextY = j + dir[k][1];
if (nextX < 0 || nextX >= n || nextY < 0 || nextY >= m) continue;
int nextMark = graph[nextX][nextY];
if (set.contains(nextMark) || !islandSize.containsKey(nextMark)) continue;
set.add(nextMark);
curSize += islandSize.get(nextMark);
}
result = Math.max(result, curSize);
}
}
}
System.out.println(result);
}
}
110. 字符串接龙
题目讲解:代码随想录
重点:
- 图中的线是如何连在一起的
- 起点和终点的最短路径长度
思路:
- 初始化存储起始字符串和目标字符串 及 存储字典
int n = scanner.nextInt(); scanner.nextLine(); String[] strs = scanner.nextLine().split(" "); // 存储起始字符串和目标字符串 String beginStr = strs[0]; String endStr = strs[1]; // 存储字典 HashSet<String> strSet = new HashSet<>(); for (int i = 0; i < n; i++) strSet.add(scanner.nextLine());
- 初始化访问过的字典及队列。然后进行BFS搜索,检查替换后的字符串是否存在于字典 并 是否已经访问过。如果替换当前字符后与目标字符串相同, 则找到了最短路径。
// 记录字典中的字符串是否被访问过, 同时记录路径长度 HashMap<String, Integer> visitMap = new HashMap<>(); Deque<String> queue = new LinkedList<>(); queue.offer(beginStr); visitMap.put(beginStr, 1); // BFS搜索 while (!queue.isEmpty()) { String word = queue.poll(); int path = visitMap.get(word); // 从头到尾替换当前字符串 for (int i = 0; i < word.length(); i++) { String newWord = word; // 遍历26个字母 for (char j = 'a'; j <= 'z'; j++) { char[] ch = newWord.toCharArray(); ch[i] = j; newWord = new String(ch); // 发现替换当前字符后与目标字符串相同, 则找到了最短路径 if (newWord.equals(endStr)) { System.out.println(path + 1); return; } // 检查替换后的字符串是否存在于字典 并 是否已经访问过 if (strSet.contains(newWord) && !visitMap.containsKey(newWord)) { visitMap.put(newWord, path + 1); queue.offer(newWord); } } } }
public class StringRelay {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int n = scanner.nextInt();
scanner.nextLine();
String[] strs = scanner.nextLine().split(" ");
// 存储起始字符串和目标字符串
String beginStr = strs[0];
String endStr = strs[1];
// 存储字典
HashSet<String> strSet = new HashSet<>();
for (int i = 0; i < n; i++) {
strSet.add(scanner.nextLine());
}
// 记录字典中的字符串是否被访问过, 同时记录路径长度
HashMap<String, Integer> visitMap = new HashMap<>();
Deque<String> queue = new LinkedList<>();
queue.offer(beginStr);
visitMap.put(beginStr, 1);
// BFS搜索
while (!queue.isEmpty()) {
String word = queue.poll();
int path = visitMap.get(word);
// 从头到尾替换当前字符串
for (int i = 0; i < word.length(); i++) {
String newWord = word;
// 遍历26个字母
for (char j = 'a'; j <= 'z'; j++) {
char[] ch = newWord.toCharArray();
ch[i] = j;
newWord = new String(ch);
// 发现替换当前字符后与目标字符串相同, 则找到了最短路径
if (newWord.equals(endStr)) {
System.out.println(path + 1);
return;
}
// 检查替换后的字符串是否存在于字典 并 是否已经访问过
if (strSet.contains(newWord) && !visitMap.containsKey(newWord)) {
visitMap.put(newWord, path + 1);
queue.offer(newWord);
}
}
}
}
// 没有找到输出0
System.out.println(0);
}
}
719

被折叠的 条评论
为什么被折叠?



