算法 - 图论03(Swift版本)

135 阅读3分钟

题目1: 孤岛总面积

讲解

本例写法比较容易出错。
建议按照题解思路,沿着边先将非孤岛排除。 然后再搜索孤岛数量。

func numIsolatedIsland(_ m: Int, _ n:Int, island: [[Int]]) -> Int {
    var visited = Array(repeating: Array(repeating: false, count: n), count: m)
    var res = 0
    let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
    // 返回是否孤岛
    func dfs(_ i: Int, _ j: Int) -> Bool {
        guard i >= 0, j >= 0, i < m, j < n, island[i][j] == 1, !visited[i][j] else { return true }
        visited[i][j] = true
        var isolated = i != 0 && j != 0 && i != (m - 1) && j != (n - 1) 
        for dir in directions {
            let nextI = i + dir.0
            let nextJ = j + dir.1
            isolated = dfs(nextI, nextJ) && isolated
        }
        return isolated
    }
    
    for i in 0..<m {
        for j in 0..<n {
            if island[i][j] == 1, !visited[i][j] {
                if dfs(i, j) {
                    res += 1
                }
            }
        }
    }
    return res
}
// let isolated =  numIsolatedIsland(4, 5, island: [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 1]]) //1
let isolated =  numIsolatedIsland(4, 5, island: [[0, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 1]]) //1

题目2:沉没孤岛

讲解

和上一题孤岛总面积思路类似。

func sinkIsland(_ m: Int, _ n: Int, _ grid: [[Int]] ) {
    // 思路更加清楚一些, 先把靠边的岛屿标记为2。
    // 然后编译一遍, 把孤岛(1)沉没(改为0), 把靠边的岛(2)恢复(改为1)
    var grid = grid 
    func dfs(_ i: Int, _ j: Int) {
        guard i >= 0, j >= 0, i < m, j < n, grid[i][j] == 1 else { return }
        grid[i][j] = 2
        for dir in [(0, 1), (1, 0), (0, -1), (-1, 0)] {
            dfs(i + dir.0, j + dir.1)
        }
    }
    for i in 0..<m {
        if grid[i][0] == 1 { dfs(i, 0) }
        if grid[i][n - 1] == 1 { dfs(i, n - 1) }
    }
    for j in 0..<n {
        if grid[0][j] == 1 { dfs(0, j) }
        if grid[m - 1][j] == 1 { dfs(m, j) }
    }
    for i in 0..<m {
        for j in 0..<n {
            if grid[i][j] == 1 { grid[i][j] = 0 }
            else if grid[i][j] == 2 { grid[i][j] = 1 }
        }
    }
    print("\(grid)")
}

sinkIsland(4, 5, [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 1]]) //1

题目3:417. 太平洋大西洋水流问题

讲解


class Solution {
    func pacificAtlantic(_ heights: [[Int]]) -> [[Int]] {
        // 巧妙的思路
        // 从太平洋 和 大西洋 分别逆流而上, 有重叠的地方即为目标节点。
        let m = heights.count
        let n = heights[0].count
        var firstBoard = Array(repeating: Array(repeating: 0, count: n), count: m)
        var secondBoard = Array(repeating: Array(repeating: 0, count: n), count: m)
        let directions = [(0, 1), (1, 0), (0, -1), (-1, 0)]
        func dfs(_ i: Int, _ j: Int, _ board: inout [[Int]]) {
            guard board[i][j] == 0 else { return }
            board[i][j] = 1
            for dir in directions {
                let ii = i + dir.0 
                let jj = j + dir.1
                if ii >= 0, jj >= 0, ii < m, jj < n, heights[i][j] <= heights[ii][jj] {
                    dfs(i + dir.0, j + dir.1, &board)
                }
            }
        }
        for i in 0..<m {
            dfs(i, 0, &firstBoard)
            dfs(i, n - 1, &secondBoard)
        }
        for j in 0..<n {
            dfs(0, j, &firstBoard)
            dfs(m - 1, j, &secondBoard)
        }
        var res = [[Int]]()
        for i in 0..<m {
            for j in 0..<n {
                if firstBoard[i][j] == 1, secondBoard[i][j] == 1 {
                    res.append([i, j])
                }
            }
        }
        return res
    }
}

题目4. 建造最大岛屿

题目讲解

func buildMaxIsland(_ m: Int, _ n: Int, _ grid: [[Int]]) -> Int {
    // 统计每个岛屿大小
    // 然后遍历每个格子, 统计这个格子加上周围岛屿的大小。 找出最大值。 
    var map = [Int: Int]() 
    var grid = grid 
    let directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    var count = 0

    func dfs(_ i: Int, _ j: Int, _ mark: Int) {
        guard i >= 0, j >= 0, i < m, j < n, grid[i][j] == 1 else { return }
        grid[i][j] = mark
        count += 1
        for dir in directions {
            dfs(i + dir.0, j + dir.1, mark)
        }
    }
    var mark = 2
    var allGrid = true
    for i in 0..<m {
        for j in 0..<n {
            if grid[i][j] == 0 { allGrid = false }
            if grid[i][j] == 1 {
                count = 0
                dfs(i, j, mark)
                map[mark] = count
                mark += 1
            }
        }
    }
    if allGrid { return m * n }
    var res = 0
    var uniqueSet = [Int]()
    for i in 0..<m {
        for j in 0..<n {
            if grid[i][j] != 0 { continue }
            var area = 1
            uniqueSet.removeAll()
            for dir in directions {
                let nexti = i + dir.0
                let nextj = j + dir.1
                guard nexti >= 0, nextj >= 0, nexti < m, nextj < n else { continue }
                let islandNum = grid[nexti][nextj]
                if islandNum > 0, !uniqueSet.contains(islandNum) {
                    area += map[islandNum]!
                    uniqueSet.append(islandNum)
                }
            }
            res = max(res, area)
        }
    }
    return res
}
let area = buildMaxIsland(4, 5, [[1, 1, 0, 0, 0], [1, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 1]]) //6
print("\(area)")