Question 1 Island 母体二刷
解题步骤
Step 1: State the problem归大类
Actually, this is a Graph Problem
I want to model the problem to a Graph problem.
Step 2: Build Graph
Let me build the graph.
In my graph
my node/ vertex is every "1" cell in the matrix
edge: horizontally or vertically each one is connected with four directions with its neightbors
Step 3: 转化问题
脱马甲,这个问题其实本质上就是在解决你构建的哪个图上的什么问题
问一下面试官:OK, do you quite follow? Do you have any questions about the graph I built?
So the problem is asking me to find out the number of islands, which is actually asking me how many connected components are there in the graph I built
Step 4:这个问题在图论里面是个什么问题
Therefore this is a traversal(reachable) problem in graph
Step 5: Propose 算法对比,选择最优
DFS对点的遍历
BFS对点的遍历
对比:时间空间复杂度,商讨具体实现的细节,选择一个最好的来写
Method 1: DFS对点的遍历
public Solution {
// assumption: no duplicate edge
private static final int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private static final char LAND = '1';
private static final char WATER = '0';
private int numberOfIsland(char[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
boolean[][] visited = new boolean[grid.length][grid[0].length];
int connectedComponent = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == LAND && !visited[i][j]) {
DFSMarkVisitedOne(grid, i, j, visited);
connectedComponent++;
}
}
}
return connectedComponent;
}
private void DFSMarkVisitedOne(char[][] grid, int i , int j, boolean[][] visited) {
if (visited[i][j]) return;
visited[i][j] = true;
for (int[] dir: DIRS) {
int neiX = i + dir[0];
int neiY = j + dir[1];
if (!isValid(grid, neiX, neiY) || grid[i][j] == WATER) {
continue;
}
DFSMarkVisitedOne(grid, neiX, neiY, visited);
}
}
private boolean isValid(char[][] grid , int i, int j) {
return i >= 0 && i < grid.length && j >= 0 && j < grid[0].length;
}
}
思考:这样Mark Visited好么?
boolean[][] visited = new boolean[grid.length][grid[0].length];
space: O(m* n) for mark visited. + Call Stack: m* n
其他的mark visited 的方式
Set<Integer> visited ==> X* Col + Y ==> 含义 + overflow
Set<String> visited ==> X + "#" + Y
Set<Int[]> visited ==> Set没法对数组去重
Set<List<Integer>>visited ==> Set可以对List去重
好的写法:Set<Node> visited;
缺点1:
boolean[][] visited = new boolean[grid.length][grid[0].length];
不管我有没有走着点,都需要mark visited, 没有必要给这些0来开空间
缺点2:
DFS is a method of Recursion: Call Stack还是很容易爆栈
Method 2: BFS对点的遍历
Let me define in code what should a Node Object be looked like
如何让Set知道如何我们定义的两个Node Object是不是同一个Object? Java Specific
Override两个方法:
HashCode(unique hash value)
用来知道这个item存在hashSet/Map里哪个柜子bucked(index)的
Equals
用来知道这个柜子里这么多东西有没有和你一样的
Map or Set
What is the time to get or put or add?O(1)
It looks like O(1) BUT in reality is that true? In Worst Case, it can be O(n) Collision
Rewrite HashCode
class Node {
int row;
int col;
public Node(int row, int col) {
this.row = row;
this.col = col;
}
@Override
public int hashCode() {
return this.row * 31 + this.col *31 * 31;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!obj instanceof Node) {
return false;
}
Node temp = (Node) obj;
return this.row == temp.row && this.col == temp.col;
}
}
Space: O(E)==> O(V)
class Solution {
int row;
int col;
public Node(int row, int col) {
this.row = row;
this.col = col;
}
@Override
public int hashCode() {
return this.row * 31 + this.col *31 * 31;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!obj instanceof Node) {
return false;
}
Node temp = (Node) obj;
return this.row == temp.row && this.col == temp.col;
}
private static final int[][] DIRS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
private static final char LAND = '1';
private static final char WATER = '0';
private int numberOfIsland(char[][] grid) {
if (grid == null || grid.length == 0 || grid[0].length == 0) {
return 0;
}
boolean[][] visited = new boolean[grid.length][grid[0].length];
int connectedComponent = 0;
for (int i = 0; i < grid.length; i++) {
for (int j = 0; j < grid[0].length; j++) {
if (grid[i][j] == LAND && !visited[i][j]) {
BFSMarkVisitedAtGeneration(grid, i, j, visited);
connectedComponent++;
}
}
}
return connectedComponent;
}
private void BFSMarkVisitedAtGeneration(char[][] grid, int i, int j , Set<Node> visited) {
Deque<Node> queue = new ArrayDeque<>();
Node node = new Node(i, j);
queue.offer(node);
visited.add(node);
while (!queue.isEmpty()) {
Ndoe cur = queue.poll();
for (int[] dir : DIRS) {
int neiX = cur.row + dir[0];
int neiY = cur.col. + dir[1];
Node neighbor = new Node(neiX, neiY);
if (isValid(grid, neiX, neiY) && grid[i][j] == LAND && !visited.contains(nei)) {
queue.offer(neighbor);
visited.add(neighbor);
}
}
}
}
private boolean isValid(char[][] grid , int i, int j) {
return i >= 0 && i < grid.length && j >= 0 && j < grid[0].length;
}
}
严格的 O(V+E), maximum O(V) space
Last updated