目录

1568:使陆地分离的最少天数(2208 分)

力扣第 204 场周赛第 3 题

题目

给你一个大小为 m x n ,由若干 01 组成的二维网格 grid ,其中 1 表示陆地, 0 表示水。岛屿 由水平方向或竖直方向上相邻的 1 (陆地)连接形成。

如果 恰好只有一座岛屿 ,则认为陆地是 连通的 ;否则,陆地就是 分离的

一天内,可以将 任何单个 陆地单元(1)更改为水单元(0)。

返回使陆地分离的最少天数。

示例 1:

输入:grid = [[0,1,1,0],[0,1,1,0],[0,0,0,0]]
输出:2
解释:至少需要 2 天才能得到分离的陆地。
将陆地 grid[1][1] 和 grid[0][2] 更改为水,得到两个分离的岛屿。

示例 2:

输入:grid = [[1,1]]
输出:2
解释:如果网格中都是水,也认为是分离的 ([[1,1]] -> [[0,0]]),0 岛屿。

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 30
  • grid[i][j]01

分析

#1

观察发现,只要岛屿有对角相连的网格,那么将该 2x2 的区域内的其它网格置 0,即可让岛屿分离。

因此最多需要两天。那么:

假如一开始就没有岛屿或者多个岛屿,返回 0
遍历岛屿网格,若置为 0 后岛屿分离,返回 1
其它情况,返回 2 

计算岛屿数量,用并查集即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
def minDays(self, grid: List[List[int]]) -> int:
    def find(x):
        if f.setdefault(x,x) != x:
            f[x] = find(f[x])
        return f[x]

    def union(x, y):
        f[find(x)] = find(y)
    
    def cal(A):
        f.clear()
        for i, j in A:
            for x, y in [(i-1, j), (i, j-1), (i+1, j), (i, j+1)]:
                if (x, y) in A:
                    union((i, j), (x, y))
        return len({find((i, j)) for i,j in A})

    m, n = len(grid), len(grid[0])
    f, A = {}, {(i, j) for i in range(m) for j in range(n) if grid[i][j]}
    if cal(A) != 1:
        return 0
    return 1 if any(cal(A-{a})!=1 for a in A) else 2

时间复杂度 O(m^2*n^2),7496 ms

#2

找某个岛屿网格,使得去掉后岛屿分离,这其实就是找无向图的割点,可以用 tarjan 算法。

注意特殊情况,岛屿只有一个网格时,没有割点,但只需要 1 天

解答

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
def minDays(self, grid: List[List[int]]) -> int:
    def find(x):
        if f.setdefault(x,x) != x:
            f[x] = find(f[x])
        return f[x]

    def union(x, y):
        f[find(x)] = find(y)
    
    def cal(A):
        f.clear()
        for i, j in A:
            for x, y in [(i-1, j), (i, j-1), (i+1, j), (i, j+1)]:
                if (x, y) in A:
                    union((i, j), (x, y))
        return len({find((i, j)) for i,j in A})
    
    def tarjan(p, isroot):
        self.idx += 1
        dfn[p] = low[p] = self.idx
        tot, (i, j) = 0, p
        for q in [(i-1, j), (i, j-1), (i+1, j), (i, j+1)]:
            if q in A:
                if q not in dfn:
                    tarjan(q, False)
                    low[p] = min(low[p], low[q])
                    tot += low[q] >= dfn[p]
                else:
                    low[p] = min(low[p], dfn[q])
        if tot>int(isroot):
            cut.append(p)
    
    m, n = len(grid), len(grid[0])
    f, A = {}, {(i, j) for i in range(m) for j in range(n) if grid[i][j]}
    if len(A) == 1:
        return 1
    if cal(A) != 1:
        return 0
    cut, dfn, low, self.idx = [], {}, {}, 0
    tarjan(next(iter(A)), True)
    return 1 if cut else 2

时间复杂度 O(m*n),108 ms