DFS连通块个数
class Solution {
public void dfs(char[][] grid, int x, int y) {
if(!inArea(grid, x, y)) return;
if(grid[x][y] == '0') return;
grid[x][y] = '0';
dfs(grid, x, y+1);
dfs(grid, x, y-1);
dfs(grid, x+1, y);
dfs(grid, x-1, y);
}
public boolean inArea(char[][]grid, int x, int y) {
return y >= 0 && y < grid[0].length && x >= 0 && x < grid.length;
}
public int numIslands(char[][] grid) {
int ans = 0;
for(int i = 0; i < grid.length; i++) {
for(int j = 0; j < grid[0].length; j++) {
if(grid[i][j] == '1') {
dfs(grid, i, j);
ans++;
}
}
}
return ans;
}
}
class Solution {
int ans = 0;
boolean[] vis;
public int findCircleNum(int[][] isConnected) {
vis = new boolean[isConnected.length];
for(int i = 0;i < isConnected.length; i++) {
if(!vis[i]) {
dfs(i, isConnected);
ans++;
}
}
return ans;
}
void dfs(int i, int[][] isConnected) {
if(vis[i]) return;
vis[i] = true;
for(int j = 0;j < isConnected.length; j++) {
if(isConnected[i][j] == 1) dfs(j, isConnected);
}
}
}
BFS连通块个数
二分图相邻点不同颜色
BFS 二分图
class Solution {
public boolean isBipartite(int[][] graph) {
int n = graph.length;
int[] vis = new int[n+1];
for(int i = 0; i < n; i++) {
if(vis[i] != 0) continue;
Deque<Integer> q = new ArrayDeque<>();
q.offer(i);
vis[i] = 1;
while(!q.isEmpty()) {
int top = q.poll();
for(int v : graph[top]) {
if(vis[top] == vis[v]) return false;
if(vis[v] == 0) {
vis[v] = -vis[top];
q.offer(v);
}
}
}
}
return true;
}
}
DFS 二分图
class Solution {
int[] vis;
public boolean isBipartite(int[][] graph) {
int n = graph.length;
vis = new int[n+1];
boolean res = true;
for(int i = 0; i < n; i++) {
if(vis[i] == 0) res = res && dfs(i, 1, graph);
}
return res;
}
boolean dfs(int i, int pre, int[][] graph) {
if(vis[i] == pre) return false;
if(vis[i] == -pre) return true;
vis[i] = -pre;
boolean res = true;
for(int c : graph[i]) {
res = res && dfs(c, vis[i], graph);
}
return res;
}
}
并查集
并查集二分图
class Solution {
int[] p;
public boolean isBipartite(int[][] graph) {
int n = graph.length;
p = new int[n+1];
for(int i = 0; i < n; i++) p[i] = i;
for(int i = 0; i < n; i++) {
int[] c = graph[i];
for(int x : c) {
if(isConnect(x, i)) return false;
union(c[0], x);
}
}
return true;
}
int find(int x) {
if(x != p[x]) p[x] = find(p[x]);
return p[x];
}
void union(int x, int y) {
int px = find(x), py = find(y);
if(px == py)return;
p[px] = py;
}
boolean isConnect(int x, int y) {
return find(x) == find(y);
}
}
class Solution {
int[] p;
int ans;
public int find(int x) {
if(p[x] == x) return p[x];
return p[x] = find(p[x]);
}
public void union(int x, int y) {
if(find(x) == find(y)) return;
p[find(x)] = p[find(y)];
ans--;
}
public int numIslands(char[][] grid) {
ans = 0;
int n = grid.length, m = grid[0].length;
p = new int[n * m];
for(int i = 0; i < n; i++) {
for(int j = 0; j < m; j++) {
int idx = i * m + j;
p[idx] = idx;
if(grid[i][j] == '1') {
ans++;
}
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
int idx = i * m + j;
if(grid[i][j] == '1') {
if(i + 1 < n && grid[i+1][j] == '1') {
union(idx, (i+1)*m+j);
}
if(j + 1 < m && grid[i][j+1] == '1') {
union(idx, i*m+j+1);
}
}
}
}
return ans;
}
}
并查集+图传递关系
class Solution {
Map<String, Integer> map = new HashMap<>();
int[] p = new int[41];
double[] w = new double[41];
int find(int x) {
if(p[x] != x) {
int ori = p[x];
p[x] = find(p[x]);
w[x] *= w[ori];
}
return p[x];
}
void union(int x, int y, double val) {
int xp = find(x), yp = find(y);
if(xp == yp) return;
p[xp] = yp;
w[xp] = w[y] * val / w[x];
}
public double[] calcEquation(List<List<String>> equations, double[] values, List<List<String>> queries) {
for(int i = 0; i < 41; i++) {
w[i] = 1.0d;
p[i] = i;
}
int num = 0;
for(int i = 0; i < equations.size(); i++) {
if(!map.containsKey(equations.get(i).get(0))) {
map.put(equations.get(i).get(0), num++);
}
if(!map.containsKey(equations.get(i).get(1))) {
map.put(equations.get(i).get(1), num++);
}
union(map.get(equations.get(i).get(0)), map.get(equations.get(i).get(1)), values[i]);
}
double[] ans = new double[queries.size()];
for(int i = 0; i < queries.size(); i++) {
double tmp = -1.0d;
String a = queries.get(i).get(0), b = queries.get(i).get(1);
if(map.containsKey(a) && map.containsKey(b)) {
int rootX = find(map.get(a)), rootY = find(map.get(b));
if(rootX == rootY) tmp = w[map.get(a)]/w[map.get(b)];
}
ans[i] = tmp;
}
return ans;
}
}
并查集处理无向图环问题
class Solution {
int p[];
public int[] findRedundantConnection(int[][] edges) {
int n = edges.length;
p = new int[n+1];
for (int i = 0; i <= n; i++) {
p[i] = i;
}
for(int[] c : edges) {
if(find(c[0]) == find(c[1])) return c;
union(c[0], c[1]);
}
return new int[2];
}
int find(int x) {
if(p[x] != x) {
p[x] = find(p[x]);
} return p[x];
}
void union(int x, int y) {
int px = find(x), py = find(y);
if(px == py) return;
p[px] = py;
}
}
并查集处理有向图 环问题
class Solution {
int[] p;
public int[] findRedundantDirectedConnection(int[][] edges) {
int n = edges.length;
int[] in = new int[n+1];
int[] res = {};
p = new int[n+1];
for(int i = 1; i <= n; i++) {p[i] = i;}
for(int[] c : edges) {if(++in[c[1]] == 2) res = c;}
if(res.length != 0) {
if(check(res, edges)) return res;
else for(int[] c : edges) if(c[1] == res[1]) return c;
}
for(int i = 0; i <= n; i++) p[i] = i;
for (int[] c : edges) {
if(find(c[1]) == find(c[0])) return c;
union(c[0], c[1]);
}
return new int[2];
}
int find(int x) {
if(p[x] != x) p[x] = find(p[x]);
return p[x];
}
void union(int x, int y) {
int px = find(x), py = find(y);
if(px == py) return;
p[py] = px;
}
boolean check(int[] e, int[][] edges) {
for(int i = 0; i <= edges.length; i++) p[i] = i;
for(int[] c : edges) {
if(Arrays.equals(c, e)) continue;
if(find(c[0]) == find(c[1])) {
return false;}
union(c[0], c[1]);
}
return true;
}
}
拓扑排序 有向无环图
class Solution {
List<List<Integer>> edge = new ArrayList<>();
Deque<Integer> queue = new LinkedList<>();
public int[] findOrder(int numCourses, int[][] prerequisites) {
int[] in = new int[numCourses];
for(int i = 0; i < numCourses; i++) edge.add(new ArrayList<>());
for(int[] c : prerequisites) {
in[c[0]]++;
edge.get(c[1]).add(c[0]);
}
for (int i = 0; i < numCourses; i++) {
if(in[i] == 0) queue.push(i);
}
int ansidx = 0;
int[] ans = new int[numCourses];
int vis = 0;
while(!queue.isEmpty()) {
int top = queue.poll();
vis++;
ans[ansidx++] = top;
for(int c : edge.get(top)) {
in[c]--;
if(in[c] == 0) queue.push(c);
}
}
if(vis == numCourses) return ans;
return new int[0];
}
}
拓扑排序应用题 (反向一下拓扑)
class Solution {
int[] e, he, ne, in;
public List<Integer> eventualSafeNodes(int[][] graph) {
he = new int[graph.length]; e = new int[4*10000+1]; ne = new int[4*10000+1];
in = new int[graph.length];
Arrays.fill(he, -1);
int idx = 0;
for(int i = 0; i < graph.length; i++) {
for(int x : graph[i]) {
in[i]++;
e[idx] = i;
ne[idx] = he[x];
he[x] = idx++;
}
}
List<Integer> ans = new ArrayList<>();
Deque<Integer> q = new ArrayDeque<>();
for(int i = 0; i < graph.length; i++) {
if (in[i] == 0) {
q.offer(i);
ans.add(i);
}
}
while(!q.isEmpty()) {
int top = q.poll();
for(int c = he[top]; c != -1; c = ne[c]) {
int j = e[c];
if(--in[j] == 0) {
q.offer(j);
ans.add(j);
}
}
}
Collections.sort(ans);
return ans;
}
}
Dijkstar算法 求单源最短路径
class Solution {
int INF = Integer.MAX_VALUE/2;
int[][] w;
int[] dist;
boolean[] vis;
int n, k;
public int networkDelayTime(int[][] times, int _n, int _k) {
n = _n; k = _k;
w = new int[n+1][n+1];
dist = new int[n+1];
vis = new boolean[n+1];
for (int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) w[i][j] = i==j?0:INF;
}
for(int[] t : times) {
w[t[0]][t[1]] = t[2];
}
dijkstar();
int ans = 0;
for(int i = 1; i <= n; i++) {
ans = Math.max(dist[i], ans);
}
return ans >= INF/2 ? -1 : ans;
}
void dijkstar() {
Arrays.fill(dist, INF);
dist[k] = 0;
for(int p = 1; p <= n; p++) {
int t = -1;
for(int i = 1; i <= n; i++) {
if(!vis[i] && (t == -1 || dist[i] < dist[t])) t = i;
}
vis[t] = true;
for(int i = 1; i <= n; i++) {
dist[i] = Math.min(dist[i], dist[t] + w[t][i]);
}
}
}
}
//堆优化版本, 适用于稀疏矩阵
class Solution {
int INF = Integer.MAX_VALUE/2;
int[] dist;
boolean[] vis;
List<int[]>[] edges;
int n, k;
public int networkDelayTime(int[][] times, int _n, int _k) {
n = _n; k = _k;
dist = new int[n+1];
vis = new boolean[n+1];
edges = new List[n+1];
for(int i = 0; i <= n; i++) edges[i] = new ArrayList<>();
for(int[] t : times) {
edges[t[0]].add(new int[]{t[1],t[2]});
}
dijkstar();
int ans = 0;
for(int i = 1; i <= n;i ++) ans = Math.max(ans, dist[i]);
return ans >= INF ? -1 : ans;
}
void dijkstar() {
Arrays.fill(dist, INF);
dist[k] = 0;
PriorityQueue<int[]> deque = new PriorityQueue<>((a,b)->a[1]-b[1]);
deque.offer(new int[]{k,0});
while(!deque.isEmpty()) {
int[] top = deque.poll();
int x = top[0];
if(vis[x]) continue;
vis[x] = true;
for(int[] e : edges[x]) {
int y = e[0], d = e[1] + dist[x];
if(dist[y] > d) {
dist[y] = d;
deque.offer(new int[]{y, d});
}
}
}
}
}
Floyd算法 求多源最短路径
class Solution {
int INF = Integer.MAX_VALUE/2-1;
int[][] w;
int N;
public int networkDelayTime(int[][] times, int n, int k) {
N = n;
w = new int[n+1][n+1];
for (int i = 1; i <= n; i++) {
for(int j = 1; j <= n; j++) w[i][j] = i==j?0:INF;
}
for(int[] t : times) {
w[t[0]][t[1]] = t[2];
}
floyd();
int ans = -1;
for(int i = 1; i <= n; i++) {
ans = Math.max(w[k][i], ans);
}
return ans >= INF/2-1 ? -1 : ans;
}
void floyd() {
// floyd 基本流程为三层循环:
// 枚举中转点 - 枚举起点 - 枚举终点 - 松弛操作
for(int p = 1; p <= N; p++) {
for(int i = 1; i <= N; i++) {
for(int j = 1; j <= N; j++) {
w[i][j] = Math.min(w[i][j], w[i][p] + w[p][j]);
}
}
}
}
}
Floyd求无向图最小环
for (int k = 0; k < n; k++) {
for (int i = 0; i < k; i++) {
for (int j = i+1; j < k; j++) {
ans = Math.min(ans, dist[i][j] + g[i][k] + g[k][j]]);
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]]);
}
}
}
Bellman Ford 核心 遍历边 题目限制边
Bellman Ford/SPFA 都是基于动态规划,其原始的状态定义为 f[i][k]f[i][k]f[i][k] 代表从起点到 iii 点,且经过最多 k 条边的最短路径。这样的状态定义引导我们能够使用 Bellman Ford 来解决有边数限制的最短路问题。
787. K 站中转内最便宜的航班
class Solution {
int INF = Integer.MAX_VALUE/2;
int[] dist;
int[] e, ne, he, w;
public int findCheapestPrice(int _n, int[][] flights, int src, int dst, int k) {
int n = flights.length;
dist = new int[_n];
k = k+1;
Arrays.fill(dist, INF);
dist[src] = 0;
int idx = 0;
int ans = bf(k, flights, dst);
return ans >= Integer.MAX_VALUE/2 ? -1 : ans;
}
int bf(int k, int[][] flights, int dst) {
for(int limit = 0; limit < k; limit++) {
int[] clone = dist.clone();
for(int[] c : flights) {
int x = c[0], y = c[1], w = c[2];
dist[y] =Math.min(dist[y], clone[x] + w);
}
}
return dist[dst];
}
}