再开下一个坑,图论专题居然以前都刷过了,三道Medium也没什么好说的,直接过
994. Rotting Oranges[Medium]
发现一个很神奇的事,这一题我再5年前的时候做,还是个Easy,现在已经涨到Medium了。看来随着通货膨胀,连Leetcode的题难度也跟着一起膨胀了
看了一下,原先的思路是拆分成三个函数,check用来检测好橘子的数量,legal用于判断是否搜索到边界,grow用于进行新的一天的搜索。
算一下时间复杂度,假设区域大小为 ,最终需要
天搜索完。单次grow需要往四个方向扩展,加一次原图恢复,总计
的复杂度,单次check复杂度为
,每天的判断包含一次grow和两次check,总计
,再加一次初始化的check。整个流程的总复杂度为
LeetCodeGOGOGO刷题记06——夯实基础(预处理)_Rotting Oranges-CSDN博客
接下来开始我的表演,直接bfs
先算一下时间复杂度,假设包含 个新鲜的橘子和
个坏掉的橘子,
。一次初始化的
,加上搜索节点
,总计
。明显快多了
200. Number of Islands[Medium]
思路:典型的dfs,和之前的回溯专题极其类似,那就不多说了,直接上代码
/*
Author Owen_Q
*/
public class IslandsNumbers {
public static int numIslands(char[][] grid) {
int n = grid.length;
int m = grid[0].length;
int count = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (grid[i][j] == '1') {
count++;
dfs(grid, i, j);
}
}
}
return count;
}
private static void dfs(char[][] grid, int i, int j) {
int n = grid.length;
int m = grid[0].length;
if (i < 0 || i >= n || j < 0 || j >= m || grid[i][j] == '0') {
return;
}
grid[i][j] = '0';
dfs(grid, i - 1, j);
dfs(grid, i + 1, j);
dfs(grid, i, j - 1);
dfs(grid, i, j + 1);
}
}
207. Course Schedule[Medium]
思路:这就是个典型的拓扑排序判环问题。那么经典的BFS和DFS,刚好都来试一下
BFS
BFS就是经典队列问题,用一个队列来维护入度为0的节点。遍历队列中的点,将每个点的后继节点入度减一,并将入度减为0的节点放入队列中。若拓扑中存在环,则环上点永远不会进入队列,也不会度数降到1,因此只要判断是否存在入度不为0的点即可。
/*
Author Owen_Q
*/
public class CourseScheduler {
public static boolean canFinishBfs(int numCourses, int[][] prerequisites) {
List<List<Integer>> nextCourses = new java.util.ArrayList<>();
for (int i = 0; i < numCourses; i++) {
nextCourses.add(new java.util.ArrayList<>());
}
int[] inDegrees = new int[numCourses];
Queue<Integer> processingCourses = new java.util.LinkedList<>();
for (int[] prerequisite : prerequisites) {
int course = prerequisite[0];
int preCourse = prerequisite[1];
nextCourses.get(preCourse).add(course);
inDegrees[course]++;
}
for (int i = 0; i < numCourses; i++) {
if (inDegrees[i] == 0) {
processingCourses.offer(i);
}
}
while (!processingCourses.isEmpty()) {
Integer course = processingCourses.poll();
numCourses--;
for (Integer nextCourse : nextCourses.get(course)) {
inDegrees[nextCourse]--;
if (inDegrees[nextCourse] == 0) {
processingCourses.offer(nextCourse);
}
}
}
return numCourses == 0;
}
}
DFS
DFS其实就是经典的递归问题,需要用一个数组来记录每个点的访问情况。这里可以维护一个点的状态机。包含未访问,访问中和访问完成三种状态,访问中和访问完成分别对应dfs的入口和出口处。由于递归是个回溯问题,因此需要从后往前递推,当回溯到访问中的节点时即表示出现环,否则则表示顺利访问。于是遍历每个节点看能否顺利访问完所有节点即可
/*
Author Owen_Q
*/
public class CourseScheduler {
public static boolean canFinishDfs(int numCourses, int[][] prerequisites) {
int[] visited = new int[numCourses];
List<List<Integer>> preCourses = new java.util.ArrayList<>();
for (int i = 0; i < numCourses; i++) {
preCourses.add(new java.util.ArrayList<>());
}
for (int[] prerequisite : prerequisites) {
int course = prerequisite[0];
int preCourse = prerequisite[1];
preCourses.get(course).add(preCourse);
}
for (int i = 0; i < numCourses; i++) {
if (visited[i] == 0) {
if (canNotFinishDfs(i, visited, preCourses)) {
return false;
}
}
}
return true;
}
private static boolean canNotFinishDfs(int course, int[] visited, List<List<Integer>> preCourses) {
if (visited[course] == 0) {
visited[course] = 1;
for (Integer preCourse : preCourses.get(course)) {
if (canNotFinishDfs(preCourse, visited, preCourses)) {
return true;
}
}
} else if (visited[course] == 1) {
return true;
}
visited[course] = 2;
return false;
}
}
完结撒花