Skip to content

Commit c48a7ea

Browse files
committed
Add: Add 2025/1/31
1 parent aa3f365 commit c48a7ea

File tree

2 files changed

+271
-0
lines changed

2 files changed

+271
-0
lines changed

827-Making A Large Island/Note.md

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
# 827. Making A Large Island
2+
3+
You are given an `n x n` binary matrix `grid`.
4+
You are allowed to change at most one `0` to be `1`.
5+
6+
Return the size of the largest island in `grid` after applying this operation.
7+
8+
An island is a 4-directionally connected group of `1`s.
9+
10+
## 基礎思路
11+
12+
我們可以先把所有島嶼找出來,並給他們編號,紀錄每個島嶼的大小。
13+
然後我們遍歷所有的"海洋",將其變成"陸地",並把新的島嶼的大小計為 1 加上四周的島嶼大小。
14+
這樣就能有效的找出最大的島嶼。
15+
16+
> Tips:
17+
> - 我們可以用 DFS 或 BFS 來找出島嶼。並給予編號,紀錄大小。
18+
> - 為了進一步減少記憶體使用,我們可以利用 `grid` 來紀錄每個島嶼的編號。由於 `grid` 中的 0 與 1 已經被使用,我們可以用 2 以上的數字來表示島嶼的編號。
19+
20+
## 解題步驟
21+
22+
### Step 1: 初始化起點 id 與 大小 Set
23+
24+
```typescript
25+
// 由於 `grid` 是 n x n 的二維陣列,我們紀錄一個 n 即可
26+
const n = grid.length;
27+
28+
// 島嶼的編號從 2 開始,以區分 1 與 0
29+
let currentIslandId = 2;
30+
31+
// 紀錄每個島嶼的大小
32+
const islandSizes: Record<number, number> = {};
33+
```
34+
35+
### Step 2: 定義 DFS 函數
36+
37+
```typescript
38+
function dfs(row: number, col: number, islandId: number): void {
39+
// 基礎情況:超出邊界或不是當前島嶼的一部分
40+
if (row < 0 || col < 0 || row >= n || col >= n || grid[row][col] !== 1) {
41+
return;
42+
}
43+
44+
grid[row][col] = islandId; // 標記當前位置為當前島嶼的一部分
45+
islandSizes[islandId]++; // 增加當前島嶼的大小
46+
47+
// 遞歸檢查四周的位置
48+
dfs(row - 1, col, islandId);
49+
dfs(row + 1, col, islandId);
50+
dfs(row, col - 1, islandId);
51+
dfs(row, col + 1, islandId);
52+
}
53+
```
54+
55+
### Step 3: 遍歷所有位置,找出島嶼
56+
57+
```typescript
58+
for (let row = 0; row < n; row++) {
59+
for (let col = 0; col < n; col++) {
60+
// 跳過水域或已經標記過的島嶼
61+
if (grid[row][col] !== 1) {
62+
continue;
63+
}
64+
65+
// 初始當前島嶼的大小
66+
islandSizes[currentIslandId] = 0;
67+
68+
// 用 DFS 找出當前島嶼的大小並標記方格
69+
dfs(row, col, currentIslandId);
70+
71+
// 移動到下一個島嶼 id
72+
currentIslandId++;
73+
}
74+
}
75+
```
76+
77+
### Step 4: Helper 函數,計算相鄰島嶼的大小
78+
79+
```typescript
80+
function getConnectedIslandSize(row: number, col: number, visitedIslands: Set<number>): number {
81+
// 基礎情況:超出邊界或是水域
82+
if (row < 0 || col < 0 || row >= n || col >= n || grid[row][col] <= 1) {
83+
return 0;
84+
}
85+
86+
// 取得當前位置的島嶼編號
87+
const islandId = grid[row][col];
88+
if (visitedIslands.has(islandId)) {
89+
return 0;
90+
}
91+
92+
visitedIslands.add(islandId); // 標記當前島嶼已經被計算過
93+
return islandSizes[islandId]; // 回傳當前島嶼的大小
94+
}
95+
```
96+
97+
### Step 5: 遍歷所有水域,找出最大島嶼
98+
99+
```typescript
100+
let maxIslandSize = 0;
101+
102+
// 旗標:是否有水域
103+
let haveZeroCell = false;
104+
105+
for (let row = 0; row < n; row++) {
106+
for (let col = 0; col < n; col++) {
107+
if (grid[row][col] === 0) {
108+
// 我們找到了水域,設定旗標
109+
haveZeroCell = true;
110+
111+
// 追蹤已經計算過的島嶼
112+
const visitedIslands = new Set<number>();
113+
114+
// 計算潛在的島嶼大小
115+
let potentialSize = 1; // 由於我們將水域變成陸地,所以大小起始為 1
116+
117+
// 檢查四周的島嶼
118+
potentialSize += getConnectedIslandSize(row - 1, col, visitedIslands);
119+
potentialSize += getConnectedIslandSize(row + 1, col, visitedIslands);
120+
potentialSize += getConnectedIslandSize(row, col - 1, visitedIslands);
121+
potentialSize += getConnectedIslandSize(row, col + 1, visitedIslands);
122+
123+
// 更新最大島嶼大小
124+
maxIslandSize = Math.max(maxIslandSize, potentialSize);
125+
}
126+
}
127+
}
128+
```
129+
130+
### Step 6: 判定是否有水域,回傳結果
131+
132+
```typescript
133+
// 如果有水域,回傳最大島嶼大小;否則回傳 n * n (所有方格都是島嶼)
134+
return haveZeroCell ? maxIslandSize : n * n;
135+
```
136+
137+
## 時間複雜度
138+
- 計算島嶼大小會使用 DFS,由於不會重複計算,所以時間複雜度為 $O(n^2)$
139+
- 檢查所有水域的四周島嶼大小,會需要遍歷所有方格,所以時間複雜度為 $O(n^2)$
140+
- 總時間複雜度為 $O(n^2)$
141+
142+
> $O(n^2)$
143+
144+
## 空間複雜度
145+
- 紀錄島嶼大小的 `islandSizes` 在最極端的情況下 (即棋盤狀的島嶼) 會使用有 $\frac{n^2}{2}$ 個島嶼,所以空間複雜度為 $O(n^2)$
146+
- DFS 遞歸會最差情況下使用 $O(n^2)$ 的堆疊空間
147+
- 總空間複雜度為 $O(n^2)$
148+
149+
> $O(n^2)$

827-Making A Large Island/answer.ts

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/**
2+
* Finds the size of the largest island that can be formed by changing at most one `0` to `1`.
3+
* An island is defined as a 4-directionally connected group of `1`s.
4+
*
5+
* @param grid - The input n x n binary grid.
6+
* @returns The size of the largest island after flipping one `0` to `1`.
7+
*/
8+
function largestIsland(grid: number[][]): number {
9+
const n = grid.length;
10+
11+
// Island IDs start from 2 to distinguish from 1s and 0s
12+
let currentIslandId = 2;
13+
14+
// Maps islandId to its size
15+
const islandSizes: Record<number, number> = {};
16+
17+
/**
18+
* Performs DFS to label the current island and count its size.
19+
*
20+
* @param row - The current row index.
21+
* @param col - The current column index.
22+
* @param islandId - The ID assigned to the current island.
23+
*/
24+
function dfs(row: number, col: number, islandId: number): void {
25+
// Base case: Out of bounds or not part of the current island
26+
if (row < 0 || col < 0 || row >= n || col >= n || grid[row][col] !== 1) {
27+
return;
28+
}
29+
30+
grid[row][col] = islandId; // Label this cell with the current islandId
31+
islandSizes[islandId]++; // Increment the size of the current island
32+
33+
// Explore all 4 directions
34+
dfs(row - 1, col, islandId);
35+
dfs(row + 1, col, islandId);
36+
dfs(row, col - 1, islandId);
37+
dfs(row, col + 1, islandId);
38+
}
39+
40+
/**
41+
* 1. Label all islands and calculate their sizes
42+
*/
43+
for (let row = 0; row < n; row++) {
44+
for (let col = 0; col < n; col++) {
45+
// Skip water cells and already labeled islands
46+
if (grid[row][col] !== 1) {
47+
continue;
48+
}
49+
50+
// Initialize the size of the current island
51+
islandSizes[currentIslandId] = 0;
52+
53+
// Perform DFS to label the current island and count its size
54+
dfs(row, col, currentIslandId);
55+
56+
// Move to the next island ID
57+
currentIslandId++;
58+
}
59+
}
60+
61+
/**
62+
* Calculates the size contributed by neighboring islands when flipping a `0` to `1`.
63+
*
64+
* @param row - The row index of the `0` cell.
65+
* @param col - The column index of the `0` cell.
66+
* @param visitedIslands - Set to track visited islands and avoid double counting.
67+
* @returns The size contribution of neighboring islands.
68+
*/
69+
function getConnectedIslandSize(row: number, col: number, visitedIslands: Set<number>): number {
70+
// Out of bounds or water cell or already visited island
71+
if (row < 0 || col < 0 || row >= n || col >= n || grid[row][col] <= 1) {
72+
return 0;
73+
}
74+
75+
// Get the island ID of the neighboring island
76+
const islandId = grid[row][col];
77+
if (visitedIslands.has(islandId)) {
78+
return 0;
79+
}
80+
81+
visitedIslands.add(islandId); // Mark this island as visited
82+
return islandSizes[islandId]; // Return its size
83+
}
84+
85+
let maxIslandSize = 0;
86+
87+
// Flag to check if any 0 was found in the grid
88+
let haveZeroCell = false;
89+
90+
/**
91+
* 2. Check each `0` cell to find the maximum possible island size.
92+
*/
93+
for (let row = 0; row < n; row++) {
94+
for (let col = 0; col < n; col++) {
95+
if (grid[row][col] === 0) {
96+
// A 0 was found, so flag it
97+
haveZeroCell = true;
98+
99+
// Track visited neighboring islands
100+
const visitedIslands = new Set<number>();
101+
102+
// Calculate the potential island size by flipping this 0
103+
let potentialSize = 1; // Start with 1 for the flipped 0 itself
104+
105+
// Check the size of neighboring islands in 4 directions
106+
potentialSize += getConnectedIslandSize(row - 1, col, visitedIslands);
107+
potentialSize += getConnectedIslandSize(row + 1, col, visitedIslands);
108+
potentialSize += getConnectedIslandSize(row, col - 1, visitedIslands);
109+
potentialSize += getConnectedIslandSize(row, col + 1, visitedIslands);
110+
111+
// Update the maximum island size
112+
maxIslandSize = Math.max(maxIslandSize, potentialSize);
113+
}
114+
}
115+
}
116+
117+
/**
118+
* 3. Return the maximum island size after flipping one `0` to `1`.
119+
* If no `0` was found, return the size of the entire grid.
120+
*/
121+
return haveZeroCell ? maxIslandSize : n * n;
122+
}

0 commit comments

Comments
 (0)