[LeetCode] 417. Pacific Atlantic Water Flow 解题报告

Given an m x n matrix of non-negative integers representing the height of each unit cell in a continent, the "Pacific ocean" touches the left and top edges of the matrix and the "Atlantic ocean" touches the right and bottom edges.

Water can only flow in four directions (up, down, left, or right) from a cell to another one with height equal or lower.

Find the list of grid coordinates where water can flow to both the Pacific and Atlantic ocean.

Note:

  1. The order of returned grid coordinates does not matter.
  2. Both m and n are less than 150.

Example:

Given the following 5x5 matrix:

  Pacific ~   ~   ~   ~   ~ 
       ~  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  *
          *   *   *   *   * Atlantic

Return:

[[0, 4], [1, 3], [1, 4], [2, 2], [3, 0], [3, 1], [4, 0]] (positions with parentheses in above matrix).

这一题看起来还有点小复杂,它需要求能够流下到太平洋和大西洋的所有的点的坐标。想直接找到这样的点,需要判断每个点能不能到两个,这样还是不太好想,不如逆向思考。先分别找到太平洋能爬上去的所有点,再找到大西洋能到达的所有点,最后求个交集就可以了,得到的结果就是能到达这两个洋的点。

具体思路:

使用两个boolean数组来存储太平洋和大西洋能到达的点,如果能到点,就把对应的值设为true,最后如果对应位置两个点都为true,那么该点就是可以到达两个洋的点,将它加入到list,输出即可。

至于针对一个洋, 如何查找它能爬上的点呢。这里也比较简单,可以利用树搜索时的方法,使用一个Queue(Stack也可以)来存储可以达到的点。首先,把所有边缘毗邻太平洋的点加入到Queue中,并就对应的boolean值置为true。然后使用while循环,循环的条件是queue.size()>0。循环的内容是,先取出(并去掉)一个点,然后判断这个点周围的四个方向,如果对应方向上的点的值>=当前点的值,那么对应方向上的点就是符合要求的点,将其加入queue,并置为true。以此类推,直到遍历到queue中没有点位置。

另一个洋也是一样的,然后循环遍历对应的点在两个boolean数组中是否都为true,输出结果即可。代码如下,复杂度大致是O(n^2),系数大于1:


public class Solution {
	boolean[][] bP;
	boolean[][] bA;
	boolean[][] bCurrent;
	Queue<int[]> que;
	int nHeight;
	int nWidth;
	int[][] matrix;

	public List<int[]> pacificAtlantic(int[][] matrix) {
	    		List<int[]> listResult = new ArrayList<>();
		if (matrix.length == 0) {
			return listResult;
		}
		/***
		 * from left to right, it is Y=width, from top to bottom, it is x=Height
		 */
		this.matrix = matrix;
		nHeight = matrix.length;
		nWidth = matrix[0].length;
		bP = new boolean[nHeight][nWidth];
		bA = new boolean[nHeight][nWidth];

		que = new LinkedList<int[]>();
		// add all pacific to queue
		bCurrent = bP;
		addToQueue(0, 0);
		for (int i = 1; i < nWidth; i++) {
			addToQueue(0, i);
		}
		for (int i = 1; i < nHeight; i++) {
			addToQueue(i, 0);
		}
		while (que.size() > 0) {
			int[] nArrCurrent = que.poll();
			explore(nArrCurrent);
		}
		// add all atlantic to queue
		bCurrent = bA;
		addToQueue(nHeight - 1, nWidth - 1);
		for (int i = 0; i < nWidth - 1; i++) {
			addToQueue(nHeight - 1, i);
		}
		for (int i = 0; i < nHeight - 1; i++) {
			addToQueue(i, nWidth - 1);
		}
		while (que.size() > 0) {
			int[] nArrCurrent = que.poll();
			explore(nArrCurrent);
		}
		for (int i = 0; i < nHeight; i++) {
			for (int j = 0; j < nWidth; j++) {
				if (bP[i][j] && bA[i][j]) {
					int[] nn = { i, j };
					listResult.add(nn);
				}
			}
		}
		return listResult;
	}

	private void addToQueue(int x, int y) {
		int[] nn = { x, y };
		bCurrent[x][y] = true;
		que.add(nn);
	}

	private boolean isBeyond(int x, int y) {
		return x >= 0 && y >= 0 && x < nHeight && y < nWidth ? true : false;
	}

	private void explore(int[] n) {
		int x = n[0];
		int y = n[1];
		int value = matrix[x][y];
		if (isBeyond(x, y - 1)) {
			tagNewPoint(x, y - 1, value);
		}
		if (isBeyond(x, y + 1)) {
			tagNewPoint(x, y + 1, value);
		}
		if (isBeyond(x - 1, y)) {
			tagNewPoint(x - 1, y, value);
		}
		if (isBeyond(x + 1, y)) {
			tagNewPoint(x + 1, y, value);
		}
	}

	private void tagNewPoint(int x, int y, int value) {
		if (matrix[x][y] >= value && bCurrent[x][y] == false) {
			bCurrent[x][y] = true;
			int[] nn = { x, y };
			que.add(nn);
		}
	}
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值