package LeetCode_827
import java.util.*
import kotlin.collections.HashMap
/**
* 827. Making A Large Island
* https://leetcode.com/problems/making-a-large-island/
*
* In a 2D grid of 0s and 1s, we change at most one 0 to a 1.
After, what is the size of the largest island? (An island is a 4-directionally connected group of 1s).
Example 1:
Input: [[1, 0], [0, 1]]
Output: 3
Explanation: Change one 0 to 1 and connect two 1s, then we get an island with area = 3.
* */
class Solution {
/*
* Solution: DFS,BFS,HashMap,HashSet, Time complexity:O(mn), Space complexity:O(mn);
* 1. DFS to find out the large island and save every island'id in map and mapping size of island,
* 2. BFS to determine what's max island size is when we change zeros to ones, and we use HashSet to help us sum up the
* island with same unique ID,
* */
fun largestIsland(grid: Array<IntArray>): Int {
if (grid == null || grid.isEmpty()) {
return 0
}
var max = 0
//because grid has contains 0,1
var isLandId = 2
//key: islandId, value:size the island
val map = HashMap<Int, Int>()
val m = grid.size
val n = grid[0].size
for (i in 0 until m) {
for (j in 0 until n) {
//when we meet island, start to find the island size
if (grid[i][j] == 1) {
val size = islandSize(grid, i, j, isLandId)
//keep update the max area
max = Math.max(max,size)
//mapping the islandId and its area size
map.put(isLandId, size)
//increase the islandId to ensure have unique id
isLandId++
}
}
}
//start bfs
val queue = LinkedList<Pair<Int, Int>>()
//4 directions
val directions = intArrayOf(0, 1, 0, -1, 0)
//queue to save all non island
for (i in 0 until m) {
for (j in 0 until n) {
if (grid[i][j] == 0) {
queue.offer(Pair(i, j))
}
}
}
while (queue.isNotEmpty()) {
val cur = queue.pop()
val set = HashSet<Int>()
//temp init is 1, because this can be change into 1
var temp = 1
for (d in 0 until 4) {
val x = cur.first + directions[d]
val y = cur.second + directions[d + 1]
if (x < 0 || y < 0 || x >= m || y >= n || grid[x][y]==0) {
continue
}
val value = grid[x][y]
if (!set.contains(value)) {
set.add(value)
temp += map.get(value) ?: 0
}
}
max = Math.max(max, temp)
}
return max
}
private fun islandSize(grid: Array<IntArray>, i: Int, j: Int, islandId: Int): Int {
if (i < 0 || j < 0 || i >= grid.size || j >= grid[0].size || grid[i][j] != 1) {
return 0
}
//set this position to current islandId
grid[i][j] = islandId
//calculate 4 directions
val left = islandSize(grid, i-1, j, islandId)
val right = islandSize(grid, i+1, j, islandId)
val top = islandSize(grid, i, j-1, islandId)
val bottom = islandSize(grid, i, j+1, islandId)
return left + right + top + bottom + 1
}
}