第一题: 547. 省份数量
加一个标志位即可简单的解决该问题
题目过于模板以至于无法评价。 但还是足足写了10min。
第二题: 802. 找到最终的安全状态
第三题: 841. 钥匙和房间
简单的遍历:dfs, bfs都可以:
class Solution {
public boolean canVisitAllRooms(List<List<Integer>> rooms) {
int n = rooms.size();
boolean[] dp = new boolean[n];
int res = 0;
Arrays.fill(dp, false);
Queue<Integer> queue = new LinkedList<>();
queue.add(0);
while (!queue.isEmpty() ) {
int now = queue.poll();
if ( !dp[now] ) {
dp[now] = true;
res++;
for (int xx:rooms.get(now) ) {
queue.add(xx);
}
}
else continue;
}
return res == n;
}
}
第四题:1129. 颜色交替的最短路径
感觉要先转化成邻接表,然后像dp一样用一个二维数组去存储到每个点的可能路径步数。
图的算法还是好难啊!
抄了几家代码学了一下。
动手尝试: 得到代码如下:
class Solution {
public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) {
int[][] res = new int[n][2];
for (int i = 0; i < n; i++) {
Arrays.fill(res[i], 2000);
}
res[0][0] = 0; res[0][1] = 0;
// 0 上一步是 红; 1 上一步是蓝
boolean flag = true;
while ( flag ) {
flag = false;
for (int[] red: redEdges) {
if ( res[red[0]][1] > 101) continue;
// 就是该位置已经可达。
if (res[red[0]][1] +1 < res[red[1]][0]) {
res[red[1]][0] = res[red[0]][1] +1;
flag = true;
}
}
for (int[] blue: blueEdges) {
if ( res[blue[0]][0] > 101 ) continue;
if (res[blue[0]][0] +1 < res[blue[1]][1]) {
res[blue[1]][1] = res[blue[0]][0] +1;
flag = true;
}
}
}
int[] real_res = new int[n];
for (int i = 0; i < n; i ++) {
real_res[i] = Math.min(res[i][0], res[i][1]);
if (real_res[i] > 101) {
real_res[i] = -1;
}
}
return real_res;
}
}
第五题: 1376. 通知所有员工所需的时间
很容易想到自底向上, 使用dfs可以秒出。
class Solution {
// Integer.MAX_VALUE
int[] time;
int[] ma;
int[] in;
public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) {
ma = manager; in = informTime;
time = new int[n];
Arrays.fill(time, Integer.MAX_VALUE);
for (int i = 0; i < n; i ++) {
time[i] = dfs(i);
}
int res = 0;
for (int i = 0; i < n; i++) {
res = Math.max(res, time[i]);
}
return res;
}
int dfs (int id) {
if (ma[id] == -1) return in[id];
if (time[id] != Integer.MAX_VALUE) {
return time[id];
}
time[id] = dfs(ma[id]) + in[id];
return time[id];
}
}
每次写递归都有一种戛然而止的感觉。
啥时候java加一个记忆化搜索的缓存啊? 每次这种情况都要自己实现一次。
第六题: 1466. 重新规划路线
class Solution {
public int minReorder(int n, int[][] connections) {
int res = 0;
boolean[] dp = new boolean[n];
boolean[] road_process = new boolean[n-1];
Arrays.fill (dp, false);
Arrays.fill (road_process, false);
boolean flag = true;
dp[0] = true;
while ( flag ) {
flag = false;
for (int i = 0; i < n-1; i++) {
if (road_process[i]) continue;
flag = true;
int source = connections[i][0], dst = connections[i][1];
if ( dp[dst] ) {
road_process[i] = true;
dp[source] = true;
}
else if ( dp[source] ) {
road_process[i] = true;
res++;
dp[dst] = true;
}
}
}
return res;
}
}
可能是最慢的方法。
使用bfs可能更快点。
我决定先转化成邻接矩阵形式, 得到代码如下:
class Solution {
public int minReorder(int n, int[][] connections) {
int[][] matrix = new int[n][n];
for (int[] con:connections) {
matrix[con[0]][con[1]] = 1;
matrix[con[1]][con[0]] = -1;
}
Queue<Integer> queue = new LinkedList<>();
int res = 0;
queue.add(0);
while (!queue.isEmpty()) {
int now = queue.poll();
for (int i = 0; i < n; i++) {
if (matrix[i][now] == 1) {
queue.add(i);
matrix[now][i] = 0;
} else if (matrix[i][now] == -1) {
queue.add(i);
res ++;
matrix[i][now] = 1;
matrix[now][i] = 0;
}
}
}
return res;
}
}
果不其然,超时了,图是个稀疏图,因此应该用list存储更河里一点。
想了一下怎么存: 感觉要写出来 List<int[]>[] 这种数据结构出来了.。参考一下大佬的写法:
class Solution {
public int minReorder(int n, int[][] connections) {
List<Integer>[] adjacentArr = new List[n];
for (int i = 0; i < n; i++) {
adjacentArr[i] = new ArrayList<Integer>();
}
for (int[] connection : connections) {
adjacentArr[connection[0]].add(connection[1]);
adjacentArr[connection[1]].add(connection[0]);
}
int[] levels = new int[n];
Arrays.fill(levels, -1);
levels[0] = 0;
Queue<Integer> queue = new ArrayDeque<Integer>();
queue.offer(0);
while (!queue.isEmpty()) {
int city = queue.poll();
List<Integer> adjacent = adjacentArr[city];
for (int next : adjacent) {
if (levels[next] < 0) {
levels[next] = levels[city] + 1;
queue.offer(next);
}
}
}
int reorder = 0;
for (int[] connection : connections) {
if (levels[connection[0]] < levels[connection[1]]) {
reorder++;
}
}
return reorder;
}
}
原来可以在遍历的时候先不着急更改录得方向,不然也不好判断, 先当作双向图遍历并记录每个节点的层级,以为这个实际上是要变成一个树的, 所以最终层次就应该跟书的方向一致。
第七题: 797. 所有可能的路径
简单的回溯, 简单题学语法:
class Solution {
List<List<Integer>> ans = new ArrayList<List<Integer>>();
Deque<Integer> stack = new ArrayDeque<Integer>();
public List<List<Integer>> allPathsSourceTarget(int[][] graph) {
stack.offerLast(0);
dfs(graph, 0, graph.length - 1);
return ans;
}
public void dfs(int[][] graph, int x, int n) {
if (x == n) {
ans.add(new ArrayList<Integer>(stack));
return;
}
for (int y : graph[x]) {
stack.offerLast(y);
dfs(graph, y, n);
stack.pollLast();
}
}
}
都要忘记list 的操作了:
ans.add(new ArrayList<Integer>(stack));
stack.offerLast(y);
stack.pollLast();
第八题: 1192. 查找集群内的关键连接
一眼不会,但感觉是去找到所有的环,不组成环的连接就不是。