精品推荐:
网上看到一网友发文称某211大学今年软件工程计划招生1900人,我有点不太相信,所以还特意去他们学校的招生官网查了下,结果发现他们学校今年软件工程的录取人数是1871人。
就算一个班30人,也要60个班,网友评论:在这养猪呢?找到工作的能有19个就不错了。
官网查询的录取人数:
--------------下面是今天的算法题--------------
来看下今天的算法题,这题是LeetCode的第417题:太平洋大西洋水流问题。
问题描述
来源:LeetCode第417题
难度:中等
有一个 m × n 的矩形岛屿,与 太平洋 和 大西洋 相邻。“太平洋” 处于大陆的左边界和上边界,而 “大西洋” 处于大陆的右边界和下边界。
这个岛被分割成一个由若干方形单元格组成的网格。给定一个 m x n 的整数矩阵 heights , heights[r][c] 表示坐标 (r, c) 上单元格 高于海平面的高度 。
岛上雨水较多,如果相邻单元格的高度小于或等于当前单元格的高度,雨水可以直接向北、南、东、西流向相邻单元格。水可以从海洋附近的任何单元格流入海洋。
返回网格坐标 result 的 2D 列表 ,其中 result[i] = [ri, ci] 表示雨水从单元格 (ri, ci) 流动 既可流向太平洋也可流向大西洋 。
示例1:
输入: 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
问题分析
这题很绕,总结起来实际上就一句话:哪些位置的水既能流到太平洋又能流到大西洋。
直接计算比较麻烦,我们先计算哪些位置的水可以流到太平洋,在计算哪些位置的水可以流到大西洋,最后在枚举所有的位置,判断哪些位置的水既能流到太平洋又能流到大西洋。
我们知道太平洋沿岸的水肯定是能流到太平洋的,水往低处流,这里我们逆向思维,让水往高处流。从太平洋沿岸的位置开始遍历,如果下一个位置比当前位置高,说明下一个位置一定可以通过当前位置流到太平洋的,如下图所示。同理大西洋也一样。
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
笔者简介
博哥,真名:王一博,毕业十多年,《算法秘籍》作者,专注于数据结构和算法的讲解,在全球30多个算法网站中累计做题2000多道,在公众号中写算法题解800多题,对算法题有自己独特的解题思路和解题技巧,喜欢的可以给个关注,也可以下载我整理的1000多页的PDF算法文档。