【Leetcode】827. Making A Large Island
題目地址:
https://leetcode.com/problems/making-a-large-island/
給定一個二維 0 − 1 0-1 0−1矩陣,允許將其中的某一個 0 0 0變為 1 1 1,問能得到的最大的 1 1 1連通塊的面積(即 1 1 1的數量)。
法1:並查集。這個問題的關鍵在於,當遍歷到 0 0 0的時候,將其變為 1 1 1之後連通了其的四個鄰居,但不知道這四個鄰居是屬於不同連通塊的還是屬於相同連通塊的,如果屬於相同連通塊,就會造成重複計算的問題。這時候並查集可以解決這個問題,當兩個節點在並查集的樹的祖宗節點相等,就說明它們是屬於同一個連通塊的。這樣就能避免重複計算。同時也需要注意矩陣全是 1 1 1的情況,這時直接返回矩陣的面積即可。程式碼如下:
import java.util.*;
public class Solution {
class Pair {
int x, y;
public Pair(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
Pair pair = (Pair) o;
return x == pair.x && y == pair.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
class UnionFind {
Map<Pair, Pair> parent;
Map<Pair, Integer> size;
public UnionFind() {
parent = new HashMap<>();
size = new HashMap<>();
}
public void add(Pair x) {
if (!parent.containsKey(x)) {
parent.put(x, x);
size.put(x, 1);
}
}
// 找到x的祖宗節點
public Pair find(Pair x) {
add(x);
if (!x.equals(parent.get(x))) {
parent.put(x, find(parent.get(x)));
}
return parent.get(x);
}
public void union(Pair x, Pair y) {
Pair px = find(x), py = find(y);
if (px.equals(py)) {
return;
}
parent.put(px, py);
size.put(py, size.get(px) + size.get(py));
}
public int getSize(Pair x) {
return size.get(find(x));
}
}
public int largestIsland(int[][] grid) {
int m = grid.length, n = grid[0].length;
UnionFind uf = new UnionFind();
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
// 接下來將1連通塊都union起來
if (grid[i][j] == 1) {
Pair cur = new Pair(i, j);
uf.add(cur);
int[] d = {1, 0, -1, 0, 1};
for (int k = 0; k < 4; k++) {
int nextI = i + d[k], nextJ = j + d[k + 1];
if (0 <= nextI && nextI < m && 0 <= nextJ && nextJ < n && grid[nextI][nextJ] == 1) {
Pair next = new Pair(nextI, nextJ);
uf.union(cur, next);
}
}
}
}
}
int res = 0;
// 記錄有沒有找到0
boolean found = false;
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 0) {
found = true;
Set<Pair> set = new HashSet<>();
int area = 1;
int[] d = {1, 0, -1, 0, 1};
for (int k = 0; k < 4; k++) {
int nextI = i + d[k], nextJ = j + d[k + 1];
if (0 <= nextI && nextI < m && 0 <= nextJ && nextJ < n && grid[nextI][nextJ] == 1) {
Pair next = new Pair(nextI, nextJ);
// 找到鄰居的祖宗,相同祖宗的鄰居的1連通塊面積只算1次
Pair ancestor = uf.find(next);
if (!set.contains(ancestor)) {
area += uf.getSize(ancestor);
set.add(ancestor);
}
}
}
res = Math.max(res, area);
}
}
}
return found ? res : m * n;
}
}
時間複雜度 O ( m n log ∗ ( m n ) ) O(mn\log ^* (mn)) O(mnlog∗(mn)),空間 O ( m n ) O(mn) O(mn)。
註解:這個方法雖然容易想到,但雜湊表的put非常耗時。陣列並查集的版本可以參考https://blog.csdn.net/qq_46105170/article/details/109178762。
法2:BFS + 標記連通塊編號。思路是將每個 1 1 1連通塊編上號,並且用雜湊表存一下每個編號對應的 1 1 1連通塊的面積。這樣只需要保證相同編號的 1 1 1連通塊的面積不要累加兩次就行了。標記 1 1 1連通塊的過程可以用BFS來實現(當然DFS也可以,參考https://blog.csdn.net/qq_46105170/article/details/109178762)。程式碼如下:
import java.util.*;
public class Solution {
public int largestIsland(int[][] grid) {
int m = grid.length, n = grid[0].length;
int[][] ids = new int[m][n];
boolean[][] visited = new boolean[m][n];
// 存編號為key的1連通塊的面積
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0, id = 1; i < m; i++) {
for (int j = 0; j < n; j++) {
if (!visited[i][j] && grid[i][j] == 1) {
map.put(id, bfs(i, j, id, ids, grid, visited));
id++;
}
}
}
int res = 0;
boolean found = false;
int[] d = {1, 0, -1, 0, 1};
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (grid[i][j] == 0) {
found = true;
int area = 1;
Set<Integer> set = new HashSet<>();
for (int k = 0; k < 4; k++) {
int nextI = i + d[k], nextJ = j + d[k + 1];
if (inBound(nextI, nextJ, grid) && grid[nextI][nextJ] == 1) {
int id = ids[nextI][nextJ];
// 相同id的連通塊面積只累加一次
if (!set.contains(id)) {
area += map.get(id);
set.add(id);
}
}
}
res = Math.max(res, area);
}
}
}
return found ? res : m * n;
}
// 對(x, y)所在的1連通塊做BFS,返回其面積,同時將該連通塊的編號填充為id
private int bfs(int x, int y, int id, int[][] ids, int[][] grid, boolean[][] visited) {
visited[x][y] = true;
ids[x][y] = id;
int area = 0;
Queue<int[]> queue = new LinkedList<>();
queue.offer(new int[]{x, y});
int[] d = {1, 0, -1, 0, 1};
while (!queue.isEmpty()) {
area++;
int[] cur = queue.poll();
for (int i = 0; i < 4; i++) {
int nextX = cur[0] + d[i], nextY = cur[1] + d[i + 1];
if (inBound(nextX, nextY, grid) && grid[nextX][nextY] == 1 && !visited[nextX][nextY]) {
// 填充id
ids[nextX][nextY] = id;
visited[nextX][nextY] = true;
queue.offer(new int[]{nextX, nextY});
}
}
}
return area;
}
private boolean inBound(int x, int y, int[][] grid) {
return 0 <= x && x < grid.length && 0 <= y && y < grid[0].length;
}
}
時空複雜度 O ( m n ) O(mn) O(mn)。
相關文章
- [LeetCode] 695. Max Area of IslandLeetCode
- LeetCode 695. Max Area of Island javascript解決方案LeetCodeJavaScript
- [Leetcode]827.使用回溯+標記解決最大人工島問題LeetCode
- 題解:CF634A Island Puzzle
- XML資料島(XML Data Island) (轉)XML
- Making AJAX Applications CrawlableAPP
- Making Whole Database Backups with RMANDatabase
- Making YACC output an AST (token tree)AST
- LOB(large object)Object
- oracle large poolOracle
- Making Kotlin Ready for Data ScienceKotlin
- Making training mini-batchesAIBAT
- Making It Big in Software書名徵集
- ORACLE LARGE MEMORY(zt)Oracle
- Large SGA On LinuxLinux
- Making Games with Python & Pygame 中文翻譯GAMPython
- LARGE DELETE快速刪除delete
- Making ARC and non-ARC files play nice together
- innodb plugin-Making Buffer Cache Scan ResistantPlugin
- Core Text Tutorial for iOS : Making a Magazine App 翻譯iOSAPP
- insert:key too large to index…Index
- 文獻學習——Making Deduction More Effective in SAT Solvers
- oracle 在 aix上large page特性OracleAI
- build a large e-commerce websiteUIWeb
- Awesome-LLM: a curated list of Large Language Model
- volley建立標準的網路請求(Making a Standard Request)
- ORA-00607: Internal error occurred while making a change to a data blockErrorWhileBloC
- Merge two videos into a large resolution videoIDE
- db2 sms tablespace 不支援large tablespaceDB2
- Tips for Navigating Large Game Code BasesGAM
- 有關SQL ID with large Version Count encountered.SQL
- LISA: Reasoning Segmentation via Large Language ModelSegmentation
- Linux Hugepage ,AMM及 USE_LARGE_PAGES - 4Linux
- Linux Hugepage ,AMM及 USE_LARGE_PAGES - 3Linux
- Linux Hugepage ,AMM及 USE_LARGE_PAGES - 2Linux
- Linux Hugepage ,AMM及 USE_LARGE_PAGES - 1Linux
- Large result cache can cause sessions to spin -instance to hangSession
- Oracle USE_LARGE_PAGES初始化引數Oracle