417. Pacific Atlantic Water Flow

题目:

417. Pacific Atlantic Water Flow

  • Total Accepted: 11498
  • Total Submissions: 34789
  • Difficulty: Medium
  • Contributor: LeetCode

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).








解题思路:

这题与我之前做过的Number of Islands类似,都是将DFS运用在矩阵问题上。用DFS遍历矩阵,用两个boolean数组p和a来记录每个点是否可以到达太平洋和大西洋,然后递归地对它上下左右连通的点进行访问,直到走到边界处,将p[i][j]或a[i][j]的值赋1。若该点的下一个点能够与海洋连通,则该点也能与海洋相连。为了提高算法效率,可以在每次递归调用DFS之前先判断下一个点是否能与海洋连通,若可以则无需再调用DFS。

对一个点做完DFS之后如果p[i][j]和a[i][j]都为1则将其加入输出vector 


代码:

class Solution {
public:
	int m, n;
	vector<pair<int, int>> res;
	bool p[150][150] = {0};
	bool a[150][150] = {0};
    vector<pair<int, int>> pacificAtlantic(vector<vector<int>>& matrix) {
    	if(!res.empty())
    		res.clear();
    	if(matrix.empty())
    		return res;
        m = matrix.size();
        n = matrix[0].size();
        for(int i = 0; i < m; i++){
        	for(int j = 0; j < n; j++){
        		DFS(matrix, i, j);
        		if(p[i][j] && a[i][j]){
        			pair<int, int> temp;
        			temp.first = i;
        			temp.second = j;
        			res.push_back(temp);
        		}
        	}
        }
        return res;
    }

    void DFS(vector<vector<int>>& matrix, int i, int j){
    	if(i == 0 || j == 0)
    		p[i][j] = 1;
    	if(i == m - 1 || j == n - 1)
    		a[i][j] = 1;
    	//up 
    	if(i - 1 >= 0 && matrix[i - 1][j] <= matrix[i][j]){
    		if(p[i - 1][j])
    			p[i][j] = 1;
    		if(a[i - 1][j])
    			a[i][j] = 1;
    		if(!p[i - 1][j] && !a[i - 1][j]){
    			DFS(matrix, i - 1, j); 
    			if(p[i - 1][j])
    				p[i][j] = 1;
    			if(a[i - 1][j])
    				a[i][j] = 1;
    		}
    	}
    	//down
    	if(i + 1 < m && matrix[i + 1][j] <= matrix[i][j]){
    		if(p[i + 1][j])
    			p[i][j] = 1;
    		if(a[i + 1][j])
    			a[i][j] = 1;
    		if(!p[i + 1][j] && !a[i + 1][j]){
    			DFS(matrix, i + 1, j); 
    			if(p[i + 1][j])
	    			p[i][j] = 1;
	    		if(a[i + 1][j])
	    			a[i][j] = 1;
    		}
    	}
    	//left
    	if(j - 1 >= 0 && matrix[i][j - 1] <= matrix[i][j]){
    		if(p[i][j - 1])
    			p[i][j] = 1;
    		if(a[i][j - 1])
    			a[i][j] = 1;
    		if(!p[i][j - 1] && !a[i][j - 1]){
    			DFS(matrix, i, j - 1); 
	    		if(p[i][j - 1])
	    			p[i][j] = 1;
	    		if(a[i][j - 1])
	    			a[i][j] = 1;
    		}
    	}
    	//right
    	if(j + 1 < m && matrix[i][j + 1] <= matrix[i][j]){
    		if(p[i][j + 1])
    			p[i][j] = 1;
    		if(a[i][j + 1])
    			a[i][j] = 1;
    		if(!p[i][j + 1] && !a[i][j + 1]){
    			DFS(matrix, i, j - 1); 
    			if(p[i][j + 1])
	    			p[i][j] = 1;
	    		if(a[i][j + 1])
	    			a[i][j] = 1;
	    	}
    		
    	}
    }
};


其他答案:

做完之后看了一下solution里的解法发现可以倒过来想,把矩阵的边界点当做起点进行DFS,这样DFS树上的每一点都是可以到达海洋的,就不会存在我的做法中重复走的问题了。参考代码如下:

public class Solution {
    public List<int[]> pacificAtlantic(int[][] matrix) {
        List<int[]> res = new LinkedList<>();
        if(matrix == null || matrix.length == 0 || matrix[0].length == 0){
            return res;
        }
        int n = matrix.length, m = matrix[0].length;
        boolean[][]pacific = new boolean[n][m];
        boolean[][]atlantic = new boolean[n][m];
        for(int i=0; i<n; i++){
            dfs(matrix, pacific, Integer.MIN_VALUE, i, 0);
            dfs(matrix, atlantic, Integer.MIN_VALUE, i, m-1);
        }
        for(int i=0; i<m; i++){
            dfs(matrix, pacific, Integer.MIN_VALUE, 0, i);
            dfs(matrix, atlantic, Integer.MIN_VALUE, n-1, i);
        }
        for (int i = 0; i < n; i++) 
            for (int j = 0; j < m; j++) 
                if (pacific[i][j] && atlantic[i][j]) 
                    res.add(new int[] {i, j});
        return res;
    }
    
    int[][]dir = new int[][]{{0,1},{0,-1},{1,0},{-1,0}};
    
    public void dfs(int[][]matrix, boolean[][]visited, int height, int x, int y){
        int n = matrix.length, m = matrix[0].length;
        if(x<0 || x>=n || y<0 || y>=m || visited[x][y] || matrix[x][y] < height)
            return;
        visited[x][y] = true;
        for(int[]d:dir){
            dfs(matrix, visited, matrix[x][y], x+d[0], y+d[1]);
        }
    }
}


可以学习别人用二位数组来表示方向的方法,这样可以使得代码更加简洁。

除了DFS还可以使用BFS,使用两个队列即可,做法与DFS大同小异。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值