代码随想录算法训练营第四十六四十七天
卡码网题目:
- 110. 字符串接龙
- 105. 有向图的完全联通
- 106. 岛屿的周长
- 107. 寻找存在的路径
其他:
今日总结
往期打卡
110. 字符串接龙
跳转: 110. 字符串接龙
学习: 代码随想录公开讲解
问题:
字典 strList 中从字符串 beginStr 和 endStr 的转换序列是一个按下述规格形成的序列:
-
序列中第一个字符串是 beginStr。
-
序列中最后一个字符串是 endStr。
-
每次转换只能改变一个字符。
-
转换过程中的中间字符串必须是字典 strList 中的字符串,且strList里的每个字符串只用使用一次。
给你两个字符串 beginStr 和 endStr 和一个字典 strList,找到从 beginStr 到 endStr 的最短转换序列中的字符串数目。如果不存在这样的转换序列,返回 0。
思路:
这题的关键是如何构图,可以提前建好字典,通过遍历各位替换字母查看新建字符串是否合法来遍历下一个位置
也可以通过构建分别清除各位字母剩下字母对可能值列表的映射来确认一次转换后可能到达的位置
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
代码(字母替换):
import java.util.*;
public class Main{public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();String beginStr = scanner.next();String endStr = scanner.next();List<String> wordList = new ArrayList<>();wordList.add(beginStr);wordList.add(endStr);for(int i=0;i<n;i++){wordList.add(scanner.next());}int count = bfs(beginStr,endStr,wordList);System.out.println(count);}public static int bfs(String beginStr,String endStr,List<String> wordList){int len = 1;Set<String> set = new HashSet<>(wordList);Set<String> visited = new HashSet<>();Queue<String> queue = new LinkedList<>();visited.add(beginStr);queue.add(beginStr);queue.add(null);while(!queue.isEmpty()){String node = queue.poll();if(node==null){if(!queue.isEmpty()){len++;queue.add(null);}continue;}char[] charArrays = node.toCharArray();for(int i=0;i<charArrays.length;i++){char old = charArrays[i];for(char j = 'a';j<='z';j++){charArrays[i] = j;String newWord = new String(charArrays);if(set.contains(newWord)&&!visited.contains(newWord)){queue.add(newWord);visited.add(newWord);if(newWord.equals(endStr)) return len+1;}}charArrays[i] = old;}}return 0;}
}
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n 2 ) O(n^2) O(n2)
代码(字母映射):
import java.util.*;
class Main{public static void main(String[] args){Scanner sc = new Scanner(System.in);int N = sc.nextInt();String beginStr = sc.next();String endStr = sc.next();List<Map<String,List<String>>> maps = new ArrayList<>();for(int i=0;i<endStr.length();i++){String sub = endStr.substring(0,i)+endStr.substring(i+1);Map<String, List<String>> map = new HashMap<>();List<String> list = new ArrayList<>();list.add(endStr);map.put(sub,list);maps.add(map);}for(int i=0;i<N;i++){String tmp = sc.next();for(int j=0;j<endStr.length();j++){String sub = tmp.substring(0,j)+tmp.substring(j+1);Map<String, List<String>> map = maps.get(j);List<String> list = map.getOrDefault(sub,new ArrayList<>());list.add(tmp);map.put(sub,list);}}Set<String> vis = new HashSet<>();Queue<String> queue = new LinkedList<>();queue.add(beginStr);int ans = 1;while(!queue.isEmpty()){int l = queue.size();ans++;for(int i=0;i<l;i++){String tmp = queue.poll();for(int j=0;j<endStr.length();j++){String sub = tmp.substring(0,j)+tmp.substring(j+1);Map<String, List<String>> map = maps.get(j);List<String> list = map.getOrDefault(sub,new ArrayList<>());if(list.contains(endStr)){System.out.println(ans);return;}for(String str:list){if(vis.contains(str)) continue;vis.add(str);queue.add(str);}}}}System.out.println(0);}
}
105. 有向图的完全联通
跳转: 105. 有向图的完全联通
学习: 代码随想录公开讲解
问题:
给定一个有向图,包含 N 个节点,节点编号分别为 1,2,…,N。现从 1 号节点开始,如果可以从 1 号节点的边可以到达任何节点,则输出 1,否则输出 -1。
例:
从 1 号节点可以到达任意节点,输出 1。
思路:
直接标记好bfs即可
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
代码:
import java.util.*;class Main {private static boolean bfs(Map<Integer, List<Integer>> map, int x, int N) {Queue<Integer> queue = new LinkedList<>();Set<Integer> vis = new HashSet<>();vis.add(x);queue.add(x);while (!queue.isEmpty()) {int tmp = queue.poll();for (int i : map.getOrDefault(tmp, new ArrayList<>())) {if (vis.contains(i)) continue;queue.add(i);vis.add(i);}}return vis.size() == N;}public static void main(String[] args) {Scanner sc = new Scanner(System.in);int N = sc.nextInt();int K = sc.nextInt();Map<Integer, List<Integer>> map = new HashMap<>();for (int i = 0; i < K; i++) {int x = sc.nextInt();int y = sc.nextInt();List<Integer> list = map.getOrDefault(x, new ArrayList<>());list.add(y);map.put(x, list);}if (bfs(map, 1, N))System.out.println(1);else System.out.println(-1);}
}
106. 岛屿的周长
跳转: 106. 岛屿的周长
学习: 代码随想录公开讲解
问题:
给定一个由 1(陆地)和 0(水)组成的矩阵,岛屿是被水包围,并且通过水平方向或垂直方向上相邻的陆地连接而成的。
你可以假设矩阵外均被水包围。在矩阵中恰好拥有一个岛屿,假设组成岛屿的陆地边长都为 1,请计算岛屿的周长。岛屿内部没有水域。
例:
岛屿的周长为 14。
思路:
边长和周围不是陆地的长度是一致的(越界或水都是边界,算1单位边长),直接bfs即可
复杂度:
- 时间复杂度: O ( n m ) O(nm) O(nm)
- 空间复杂度: O ( n m ) O(nm) O(nm)
代码:
import java.util.*;class Main {public static void main(String[] args) {int ans = 0;int[][] DISTANCE = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};Scanner sc = new Scanner(System.in);int N = sc.nextInt();int M = sc.nextInt();int[][] map = new int[N][M];for (int i = 0; i < N; i++)for (int j = 0; j < M; j++)map[i][j] = sc.nextInt();for (int i = 0; i < N; i++)for (int j = 0; j < M; j++)if (map[i][j] == 1)for (int k = 0; k < 4; k++) {int n = i + DISTANCE[k][0];int m = j + DISTANCE[k][1];if (n < 0 || m < 0 || n >= map.length || m >= map[0].length || map[n][m] == 0)ans++;}System.out.println(ans);}
}
并查集理论
学习: 代码随想录公开讲解
并查集就是把同类节点串起来,用父级是否相等判断是否有关联(对于无向图而言即:是否联通)
有两种优化方法,路径压缩和按秩合并
-
路径压缩就是查找父级后递归回去的过程直接指向最前父级
-
按秩合并就是如果树深度不同小深度连到大的身上,减少最大查询深度的增加.
107. 寻找存在的路径
跳转: 107. 寻找存在的路径
学习: 代码随想录公开讲解
问题:
给定一个包含 n 个节点的无向图中,节点编号从 1 到 n (含 1 和 n )。
你的任务是判断是否有一条从节点 source 出发到节点 destination 的路径存在。
思路:
并查集模板题目
复杂度:
- 时间复杂度: O ( n ) O(n) O(n)
- 空间复杂度: O ( n ) O(n) O(n)
代码:
import java.util.Scanner;
public class Main{static int[] father;private static boolean isSamed(int a,int b){int x = find(a);int y = find(b);return x==y;}private static void join(int a,int b){int x = find(a);int y = find(b);if(x==y) return;father[y] = father[x];}private static int find(int a){return father[a]==a?a:(father[a]=find(father[a]));}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt()+1;int m = scanner.nextInt();father = new int[n];for(int i=0;i<n;i++)father[i] = i;for(int i=0;i<m;i++){int x = scanner.nextInt();int y = scanner.nextInt();join(x,y);}int source = scanner.nextInt();int destination = scanner.nextInt();System.out.println(isSamed(source,destination)?1:0);}
}
总结
练习了bfs和并查集
往期打卡
代码随想录算法训练营第四十五天
代码随想录算法训练营第四十四天
代码随想录算法训练营第四十二&四十三天
代码随想录算法训练营第四十一天
代码随想录算法训练营第四十天
代码随想录算法训练营第三十九天
代码随想录算法训练营第三十八天
代码随想录算法训练营第三十七天
代码随想录算法训练营第三十五&三十六天
代码随想录算法训练营第三十四天
代码随想录算法训练营第三十三天(补)
代码随想录算法训练营第三十二天
代码随想录算法训练营第三十一天
代码随想录算法训练营第三十天(补)
代码随想录算法训练营第二十九天
代码随想录算法训练营第二十八天
代码随想录算法训练营第二十七天(补)
代码随想录算法训练营第二十六天
代码随想录算法训练营第二十五天
代码随想录算法训练营第二十四天
代码随想录算法训练营第二十三天
代码随想录算法训练营周末四
代码随想录算法训练营第二十二天(补)
代码随想录算法训练营第二十一天
代码随想录算法训练营第二十天
代码随想录算法训练营第十九天
代码随想录算法训练营第十八天
代码随想录算法训练营第十七天
代码随想录算法训练营周末三
代码随想录算法训练营第十六天
代码随想录算法训练营第十五天
代码随想录算法训练营第十四天
代码随想录算法训练营第十三天
代码随想录算法训练营第十二天
代码随想录算法训练营第十一天
代码随想录算法训练营周末二
代码随想录算法训练营第十天
代码随想录算法训练营第九天
代码随想录算法训练营第八天
代码随想录算法训练营第七天
代码随想录算法训练营第六天
代码随想录算法训练营第五天
代码随想录算法训练营周末一
代码随想录算法训练营第四天
代码随想录算法训练营第三天
代码随想录算法训练营第二天
代码随想录算法训练营第一天