Skip to content

Commit 50e93f5

Browse files
authored
Merge pull request #68 from Jer3myYu/java-solutions-graphs
Java Chapter 13: Graphs
2 parents fef0fdd + d91c647 commit 50e93f5

11 files changed

+594
-0
lines changed
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
public class BipartiteGraphValidation {
2+
public boolean bipartiteGraphValidation(int[][] graph) {
3+
int[] colors = new int[graph.length];
4+
// Determine if each graph component is bipartite.
5+
for (int i = 0; i < graph.length; i++) {
6+
if (colors[i] == 0 && !dfs(i, 1, graph, colors)) {
7+
return false;
8+
}
9+
}
10+
return true;
11+
}
12+
13+
private boolean dfs(int node, int color, int[][] graph, int[] colors) {
14+
colors[node] = color;
15+
for (int neighbor : graph[node]) {
16+
// If the current neighbor has the same color as the current
17+
// node, the graph is not bipartite.
18+
if (colors[neighbor] == color) {
19+
return false;
20+
}
21+
// If the current neighbor is not colored, color it with the
22+
// other color and continue the DFS.
23+
if (colors[neighbor] == 0 && !dfs(neighbor, -color, graph, colors)) {
24+
return false;
25+
}
26+
}
27+
return true;
28+
}
29+
}

java/Graphs/ConnectTheDots.java

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.Collections;
4+
import java.util.List;
5+
6+
class UnionFind {
7+
int[] parent;
8+
int[] size;
9+
10+
public UnionFind(int size) {
11+
this.parent = new int[size];
12+
this.size = new int[size];
13+
for (int i = 0; i < size; i++) {
14+
this.parent[i] = i;
15+
}
16+
Arrays.fill(this.size, 1);
17+
}
18+
19+
public boolean union(int x, int y) {
20+
int repX = find(x);
21+
int repY = find(y);
22+
if (repX != repY) {
23+
if (this.size[repX] > this.size[repY]) {
24+
this.parent[repY] = repX;
25+
this.size[repX] += this.size[repY];
26+
}
27+
else {
28+
this.parent[repX] = repY;
29+
this.size[repY] += this.size[repX];
30+
}
31+
// Return True if both groups were merged.
32+
return true;
33+
}
34+
// Return False if the points belong to the same group.
35+
return false;
36+
}
37+
38+
public int find(int x) {
39+
if (x == this.parent[x]) {
40+
return x;
41+
}
42+
this.parent[x] = find(this.parent[x]);
43+
return this.parent[x];
44+
}
45+
}
46+
47+
public class ConnectTheDots {
48+
public int connectTheDots(int[][] points) {
49+
int n = points.length;
50+
// Create and populate a list of all possible edges.
51+
List<int[]> edges = new ArrayList<>();
52+
for (int i = 0; i < n; i++) {
53+
for (int j = i + 1; j < n; j++) {
54+
// Manhattan distance.
55+
int cost = Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1]);
56+
edges.add(new int[]{cost, i, j});
57+
}
58+
}
59+
// Sort the edges by their cost in ascending order.
60+
Collections.sort(edges, (a, b) -> Integer.compare(a[0], b[0]));
61+
UnionFind uf = new UnionFind(n);
62+
int totalCost, edgesAdded;
63+
totalCost = edgesAdded = 0;
64+
// Use Kruskal's algorithm to create the MST and identify its minimum cost.
65+
for (int[] edge : edges) {
66+
int cost = edge[0];
67+
int p1 = edge[1];
68+
int p2 = edge[2];
69+
// If the points are not already connected (i.e. their representatives are
70+
// not the same), connect them, and add the cost to the total cost.
71+
if (uf.union(p1, p2)) {
72+
totalCost += cost;
73+
edgesAdded++;
74+
// If n - 1 edges have been added to the MST, the MST is complete.
75+
if (edgesAdded == n - 1) {
76+
return totalCost;
77+
}
78+
}
79+
}
80+
return 0;
81+
}
82+
}

java/Graphs/CountIslands.java

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
public class CountIslands {
2+
public int countIslands(int[][] matrix) {
3+
if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
4+
return 0;
5+
}
6+
int count = 0;
7+
for (int r = 0; r < matrix.length; r++) {
8+
for (int c = 0; c < matrix[0].length; c++) {
9+
// If a land cell is found, perform DFS to explore the full
10+
// island, and include this island in our count.
11+
if (matrix[r][c] == 1) {
12+
dfs(r, c, matrix);
13+
count++;
14+
}
15+
}
16+
}
17+
return count;
18+
}
19+
20+
private void dfs(int r, int c, int[][] matrix) {
21+
// Mark the current land cell as visited.
22+
matrix[r][c] = -1;
23+
// Define direction vectors for up, down, left, and right.
24+
int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
25+
// Recursively call DFS on each neighboring land cell to continue
26+
// exploring this island.
27+
for (int[] d : dirs) {
28+
int nextR = r + d[0];
29+
int nextC = c + d[1];
30+
if (isWithinBounds(nextR, nextC, matrix) && matrix[nextR][nextC] == 1) {
31+
dfs(nextR, nextC, matrix);
32+
}
33+
}
34+
}
35+
36+
private boolean isWithinBounds(int r, int c, int[][] matrix) {
37+
return 0 <= r && r < matrix.length && 0 <= c && c < matrix[0].length;
38+
}
39+
}

java/Graphs/GraphDeepCopy.java

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import java.util.HashMap;
2+
import java.util.Map;
3+
4+
import DS.GraphNode;
5+
6+
/*
7+
// Definition of GraphNode:
8+
class GraphNode {
9+
public int val;
10+
public List<GraphNode> neighbors;
11+
public MultiLevelListNode(int val) {
12+
this.val = val;
13+
this.neighbors = new ArrayList<>();
14+
}
15+
}
16+
*/
17+
18+
public class GraphDeepCopy {
19+
public GraphNode graphDeepCopy(GraphNode node) {
20+
if (node == null) {
21+
return null;
22+
}
23+
Map<GraphNode, GraphNode> cloneMap = new HashMap<>();
24+
return dfs(node, cloneMap);
25+
}
26+
27+
private GraphNode dfs(GraphNode node, Map<GraphNode, GraphNode> cloneMap) {
28+
// If this node was already cloned, then return this previously
29+
// cloned node.
30+
if (cloneMap.containsKey(node)) {
31+
return cloneMap.get(node);
32+
}
33+
// Clone the current node.
34+
GraphNode clonedNode = new GraphNode(node.val);
35+
// Store the current clone to ensure it doesn't need to be created
36+
// again in future DFS calls.
37+
cloneMap.put(node, clonedNode);
38+
// Iterate through the neighbors of the current node to connect
39+
// their clones to the current cloned node.
40+
for (GraphNode neighbor : node.neighbors) {
41+
GraphNode clonedNeighbor = dfs(neighbor, cloneMap);
42+
clonedNode.neighbors.add(clonedNeighbor);
43+
}
44+
return clonedNode;
45+
}
46+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
public class LongestIncreasingPath {
2+
public int longestIncreasingPath(int[][] matrix) {
3+
if (matrix == null || matrix.length == 0 || matrix[0] == null || matrix[0].length == 0) {
4+
return 0;
5+
}
6+
int res = 0;
7+
int m = matrix.length;
8+
int n = matrix[0].length;
9+
int[][] memo = new int[m][n];
10+
// Find the longest increasing path starting at each cell. The
11+
// maximum of these is equal to the overall longest increasing
12+
// path.
13+
for (int r = 0; r < m; r++) {
14+
for (int c = 0; c < n; c++) {
15+
res = Math.max(res, dfs(r, c, matrix, memo));
16+
}
17+
}
18+
return res;
19+
}
20+
21+
private int dfs(int r, int c, int[][] matrix, int[][] memo) {
22+
if (memo[r][c] != 0) {
23+
return memo[r][c];
24+
}
25+
int maxPath = 1;
26+
int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
27+
// The longest path starting at the current cell is equal to the
28+
// longest path of its larger neighboring cells, plus 1.
29+
for (int[] d : dirs) {
30+
int nextR = r + d[0];
31+
int nextC = c + d[1];
32+
if (isWithinBounds(nextR, nextC, matrix) && matrix[nextR][nextC] > matrix[r][c]) {
33+
maxPath = Math.max(maxPath, 1 + dfs(nextR, nextC, matrix, memo));
34+
}
35+
}
36+
memo[r][c] = maxPath;
37+
return maxPath;
38+
}
39+
40+
private boolean isWithinBounds(int r, int c, int[][] matrix) {
41+
return 0 <= r && r < matrix.length && 0 <= c && c < matrix[0].length;
42+
}
43+
}

java/Graphs/MatrixInfection.java

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import java.util.LinkedList;
2+
import java.util.Queue;
3+
4+
public class MatrixInfection {
5+
public int matrixInfection(int[][] matrix) {
6+
int[][] dirs = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
7+
Queue<int[]> queue = new LinkedList<>();
8+
int ones, seconds;
9+
ones = seconds = 0;
10+
// Count the total number of uninfected cells and add each infected
11+
// cell to the queue to represent level 0 of the level-order
12+
// traversal.
13+
for (int r = 0; r < matrix.length; r++) {
14+
for (int c = 0; c < matrix[0].length; c++) {
15+
if (matrix[r][c] == 1) {
16+
ones += 1;
17+
} else if (matrix[r][c] == 2) {
18+
queue.offer(new int[]{r, c});
19+
}
20+
}
21+
}
22+
// Use level-order traversal to determine how long it takes to
23+
// infect the uninfected cells.
24+
while (!queue.isEmpty() && ones > 0) {
25+
// 1 second passes with each level of the matrix that's explored.
26+
seconds++;
27+
int size = queue.size();
28+
for (int i = 0; i < size; i++) {
29+
int[] pos = queue.poll();
30+
int r = pos[0];
31+
int c = pos[1];
32+
// Infect any neighboring 1s and add them to the queue to be
33+
// processed in the next level.
34+
for (int[] d : dirs) {
35+
int nextR = r + d[0];
36+
int nextC = c + d[1];
37+
if (isWithinBounds(nextR, nextC, matrix) && matrix[nextR][nextC] == 1) {
38+
matrix[nextR][nextC] = 2;
39+
ones--;
40+
queue.offer(new int[]{nextR, nextC});
41+
}
42+
}
43+
}
44+
}
45+
// If there are still uninfected cells left, return -1. Otherwise,
46+
// return the time passed.
47+
return ones == 0 ? seconds : -1;
48+
}
49+
50+
private boolean isWithinBounds(int r, int c, int[][] matrix) {
51+
return 0 <= r && r < matrix.length && 0 <= c && c < matrix[0].length;
52+
}
53+
}

java/Graphs/MergingCommunities.java

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import java.util.Arrays;
2+
3+
class UnionFind {
4+
int[] parent;
5+
int[] size;
6+
7+
public UnionFind(int size) {
8+
this.parent = new int[size];
9+
this.size = new int[size];
10+
for (int i = 0; i < size; i++) {
11+
this.parent[i] = i;
12+
}
13+
Arrays.fill(this.size, 1);
14+
}
15+
16+
public void union(int x, int y) {
17+
int repX = find(x);
18+
int repY = find(y);
19+
if (repX != repY) {
20+
// If 'repX' represents a larger community, connect
21+
// 'repY 's community to it.
22+
if (this.size[repX] > this.size[repY]) {
23+
this.parent[repY] = repX;
24+
this.size[repX] += this.size[repY];
25+
}
26+
// Otherwise, connect 'rep_x's community to 'rep_y'.
27+
else {
28+
this.parent[repX] = repY;
29+
this.size[repY] += this.size[repX];
30+
}
31+
}
32+
}
33+
34+
public int find(int x) {
35+
if (x == this.parent[x]) {
36+
return x;
37+
}
38+
// Path compression.
39+
this.parent[x] = find(this.parent[x]);
40+
return this.parent[x];
41+
}
42+
43+
public int getSize(int x) {
44+
return this.size[find(x)];
45+
}
46+
}
47+
48+
public class MergingCommunities {
49+
UnionFind uf;
50+
51+
public MergingCommunities(int n) {
52+
this.uf = new UnionFind(n);
53+
}
54+
55+
public void connect(int x, int y) {
56+
this.uf.union(x, y);
57+
}
58+
59+
public int getCommunitySize(int x) {
60+
return this.uf.getSize(x);
61+
}
62+
}

0 commit comments

Comments
 (0)