逆天,某211软件工程招1900人。网友:搁这儿养猪呢 。。

01cfd8fb46a2ad5de8b6b02693ce27a7.gif

精品推荐:

《征服数据结构》《经典图论算法》

网上看到一网友发文称某211大学今年软件工程计划招生1900人,我有点不太相信,所以还特意去他们学校的招生官网查了下,结果发现他们学校今年软件工程的录取人数是1871人。

就算一个班30人,也要60个班,网友评论:在这养猪呢?找到工作的能有19个就不错了。

71d5a1aedcb5285539b91c500cdc46b4.png

官网查询的录取人数:

a9638ccbda8aca5371871bb8717f0578.png

06a762ca344e7851670e4ce2576b0cfc.png

49b0fa9720cf4591cd280aab324f6e85.png

98f6d8eb6391a947cb0e73fad1535889.png

--------------下面是今天的算法题--------------

来看下今天的算法题,这题是LeetCode的第417题:太平洋大西洋水流问题。

问题描述

来源:LeetCode第417题

难度:中等

有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。“太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。

这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , heights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度 。

岛上雨水较多,如果相邻单元格的高度小于或等于当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。

返回网格坐标 result 的 2D 列表 ,其中 result[i] = [ri, ci] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可流向大西洋 。

示例1:

366e2799b6e6bf15b9fdf72f8d0e4c6c.jpeg

输入: heights = [[1,2,2,3,5],[3,2,3,4,4],[2,4,5,3,1],[6,7,1,4,5],[5,1,1,2,4]]

输出: [[0,4],[1,3],[1,4],[2,2],[3,0],[3,1],[4,0]]

示例2:

输入: heights = [[2,1],[1,2]]

输出: [[0,0],[0,1],[1,0],[1,1]]

  • m == heights.length

  • n == heights[r].length

  • 1 <= m, n <= 200

  • 0 <= heights[r][c] <= 10^5

问题分析

这题很绕,总结起来实际上就一句话:哪些位置的水既能流到太平洋又能流到大西洋。

直接计算比较麻烦,我们先计算哪些位置的水可以流到太平洋,在计算哪些位置的水可以流到大西洋,最后在枚举所有的位置,判断哪些位置的水既能流到太平洋又能流到大西洋。

我们知道太平洋沿岸的水肯定是能流到太平洋的,水往低处流,这里我们逆向思维,让水往高处流。从太平洋沿岸的位置开始遍历,如果下一个位置比当前位置高,说明下一个位置一定可以通过当前位置流到太平洋的,如下图所示。同理大西洋也一样。

689d6dec79c6976f91a432c07fda2459.png

JAVA:

public List<List<Integer>> pacificAtlantic(int[][] heights) {
    List<List<Integer>> ans = new ArrayList<>();
    int n = heights.length, m = heights[0].length;
    // 哪些位置可以到达太平洋
    boolean[][] pacific = new boolean[n][m];// 太平洋
    // 哪些位置可以到达大西洋
    boolean[][] atlantic = new boolean[n][m];// 大西洋
    Queue<int[]> pQueue = new LinkedList<>();
    Queue<int[]> aQueue = new LinkedList<>();
    // 四周边界
    for (int i = 0; i < n; i++) {
        pQueue.offer(new int[]{i, 0});
        aQueue.offer(new int[]{i, m - 1});
        pacific[i][0] = true;
        atlantic[i][m - 1] = true;
    }
    for (int i = 0; i < m; i++) {
        pQueue.offer(new int[]{0, i});
        aQueue.offer(new int[]{n - 1, i});
        pacific[0][i] = true;
        atlantic[n - 1][i] = true;
    }
    bfs(heights, m, n, pQueue, pacific);// 先查找能够到达太平洋的坐标
    bfs(heights, m, n, aQueue, atlantic);// 在查找能够达到大西洋的坐标

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            // 哪些位置既可以到达太平洋也可以达到大西洋
            if (pacific[i][j] && atlantic[i][j])
                ans.add(Arrays.asList(i, j));
        }
    }
    return ans;
}

int[][] dir = new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

private void bfs(int[][] heights, int m, int n, Queue<int[]> queue, boolean[][] visited) {
    while (!queue.isEmpty()) {
        int[] cur = queue.poll();
        for (int[] d : dir) {
            int x = cur[0] + d[0];
            int y = cur[1] + d[1];
            // 水如果从位置heights[x][y]流到位置[cur[0]][cur[1]],那么
            // heights[x][y]的高度必须要大于[cur[0]][cur[1]]。
            if (x < 0 || x >= n || y < 0 || y >= m || visited[x][y]
                    || heights[x][y] < heights[cur[0]][cur[1]])
                continue;
            visited[x][y] = true;// 标记可以到达
            queue.offer(new int[]{x, y});
        }
    }
}

C++:

public:
    vector<vector<int>> pacificAtlantic(vector<vector<int>> &heights) {
        vector<vector<int>> ans;
        int n = heights.size(), m = heights[0].size();
        // 哪些位置可以到达太平洋
        vector<vector<bool>> pacific(n, vector<bool>(m, false));
        // 哪些位置可以到达大西洋
        vector<vector<bool>> atlantic(n, vector<bool>(m, false));
        queue<pair<int, int>> pQueue;
        queue<pair<int, int>> aQueue;
        // 四周边界
        for (int i = 0; i < n; i++) {
            pQueue.emplace(i, 0);
            aQueue.emplace(i, m - 1);
            pacific[i][0] = true;
            atlantic[i][m - 1] = true;
        }
        for (int i = 0; i < m; i++) {
            pQueue.emplace(0, i);
            aQueue.emplace(n - 1, i);
            pacific[0][i] = true;
            atlantic[n - 1][i] = true;
        }
        bfs(heights, m, n, pQueue, pacific);// 先查找能够到达太平洋的坐标
        bfs(heights, m, n, aQueue, atlantic);// 在查找能够达到大西洋的坐标

        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                // 哪些位置既可以到达太平洋也可以达到大西洋
                if (pacific[i][j] && atlantic[i][j])
                    ans.push_back({i, j});
            }
        }
        return ans;
    }

    int dir[4][2] = {{1,  0},
                     {-1, 0},
                     {0,  1},
                     {0,  -1}};

    void bfs(vector<vector<int>> &heights, int m, int n, queue<pair<int, int>> &q, vector<vector<bool>> &visited) {
        while (!q.empty()) {
            pair<int, int> cur = q.front();
            q.pop();
            for (const auto d: dir) {
                int x = cur.first + d[0];
                int y = cur.second + d[1];
                // 水如果从位置heights[x][y]流到位置[cur[0]][cur[1]],那么
                // heights[x][y]的高度必须要大于[cur[0]][cur[1]]。
                if (x < 0 || x >= n || y < 0 || y >= m || visited[x][y]
                    || heights[x][y] < heights[cur.first][cur.second])
                    continue;
                visited[x][y] = true;// 标记可以到达
                q.emplace(x, y);
            }
        }
    }

Python:

def pacificAtlantic(self, heights: List[List[int]]) -> List[List[int]]:
    def bfs(q, visited):
        while q:
            cur = q.pop()
            for d in dirs:
                x = cur[0] + d[0]
                y = cur[1] + d[1]
                # 水如果从位置heights[x][y]流到位置[cur[0]][cur[1]],那么heights[x][y] 的高度必须要大于[cur[0]][cur[1]]。
                if x < 0 or x >= n or y < 0 or y >= m or visited[x][y] or heights[x][y] < heights[cur[0]][cur[1]]:
                    continue
                visited[x][y] = True  # 标记可以到达
                q.append([x, y])

    dirs = [[1, 0], [-1, 0], [0, 1], [0, -1]]
    ans = []
    n, m = len(heights), len(heights[0])
    # 哪些位置可以到达太平洋
    pacific = [[False for _ in range(m)] for _ in range(n)]
    # 哪些位置可以到达大西洋
    atlantic = [[False for _ in range(m)] for _ in range(n)]
    pQueue = []
    aQueue = []
    # 四周边界
    for i in range(n):
        pQueue.append([i, 0])
        aQueue.append([i, m - 1])
        pacific[i][0] = True
        atlantic[i][m - 1] = True
    for i in range(m):
        pQueue.append([0, i])
        aQueue.append([n - 1, i])
        pacific[0][i] = True
        atlantic[n - 1][i] = True
    bfs(pQueue, pacific)  # 先查找能够到达太平洋的坐标
    bfs(aQueue, atlantic)  # 在查找能够达到大西洋的坐标

    for i in range(n):
        for j in range(m):
            # 哪些位置既可以到达太平洋也可以达到大西洋
            if pacific[i][j] and atlantic[i][j]:
                ans.append([i, j])
    return ans

2c998431ae654c8967ae0fdb8950c7be.gif

笔者简介

博哥,真名:王一博,毕业十多年,《算法秘籍》作者,专注于数据结构和算法的讲解,在全球30多个算法网站中累计做题2000多道,在公众号中写算法题解800多题,对算法题有自己独特的解题思路和解题技巧,喜欢的可以给个关注,也可以下载我整理的1000多页的PDF算法文档。

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据结构和算法

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值