LintCode 1410 - Matrix Water Injection


https://github.com/cherryljr/LintCode/blob/master/Matrix%20Water%20Injection.java
Given a two-dimensional matrix, the value of each grid represents the height of the terrain.
The flow of water will only flow up, down, right and left, and it must flow from the high ground to the low ground.
As the matrix is surrounded by water, it is now filled with water from (R,C) and asked if water can flow out of the matrix.

The input matrix size is n x n, n <= 200.
Ensure that each height is a positive integer.

Example
Given
mat =
[
    [10,18,13],
    [9,8,7],
    [1,2,3]
]
R = 1, C = 1, return "YES"。

Explanation:
(1,1) →(1,2)→Outflow.

Given
mat =
[
    [10,18,13],
    [9,7,8],
    [1,11,3]
]
R = 1, C = 1, return "NO"。

Explanation:
Since (1,1) cannot flow to any other grid, it cannot flow out.
 */

/**
 * 以本题为例,这里提供了 两种 BFS 做法的的模板
 *  第一种为:在 出队列 的时候进行 结束条件 判断;
 *  第二种为:在 进队列 的时候进行 结束条件 判断。
 * 其本质就是对 结束条件 的 判断时机 不同罢了。
 * 具体的分析与比较可以看下面的详细说明。
 *
 * 这里就本题在使用 BFS 过程中没有涉及到的一些注意点进行一个补充说明:
 *  1. BFS 过程中需要使用到 level (step) 信息的话。如:需要走多少步,进行多少次编辑等。
 *  我们需要在一轮 BFS 开始之前首先获得当前 队列的长度size(),这就代表了当前层的大小与其相对应的元素,
 *  然后按照 size 的大小进行处理,之所以这么做是因为 循环中queue.size()是动态的,故必须在for循环之前就取好。
 *  当然了,我们也可以直接将 step 信息封装到每个对象中,并加入队列,但是这将耗费一定的空间。
 *  应用示例可以参考:
 *  Binary Tree Level Order Traversal (easy):
 *      https://github.com/cherryljr/LintCode/blob/master/Binary%20Tree%20Level%20Order%20Traversal.java
 *  Bus Routes (hard):
 *      https://github.com/cherryljr/LeetCode/blob/master/Bus%20Routes.java
 *  2. 依据 BFS 遍历过程中的特性(level by level),其经常被用于求最短路径。
 *  并且有时候我们会进行反向 BFS 来节省时间。(多终点,需要求每个点到终点的最短路径)
 *  应用示例可以参考:
 *  Police Distance:
 *      https://github.com/cherryljr/LintCode/blob/master/Police%20Distance.java
 *  Portal:
 *      https://github.com/cherryljr/LintCode/blob/master/Portal.java
 */

/**
 * Approach 1: BFS
 * 该做法是在 出队列 的时候判断结束,因此在入队列的时候是不需要进行结束条件判断的。
 * 相比于在 入队 时进行结束条件的判断,该写法的代码更加简洁美观一些。
 * 并且不需要对 起始点 进行条件判断。
 * 因此在不追求极致效率的情况下,很多人都会选择这种写法。
 */
public class Solution {
    /**
     * @param matrix: the height matrix
     * @param R: the row of (R,C)
     * @param C: the columns of (R,C)
     * @return: Whether the water can flow outside
     */
    public String waterInjection(int[][] matrix, int R, int C) {
        int rows = matrix.length, cols = matrix[0].length;
        // BFS 的遍历方向,我们可以利用数组存储。
        final int[][] DIRS = new int[][]{{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
        // 使用队列进行 BFS
        Queue<int[]> queue = new LinkedList<>();
        // 使用一个数据结构来记录已经遍历过的位置(有时候我们也可以通过修改原数据从而达到辨识的目的)
        // 但是修改原数据在实际工程中并不是一个好的做法
        boolean[][] visited = new boolean[rows][cols];
        // 在队列中加入 起始点的信息 并将其记录到 visited 中
        queue.offer(new int[]{R, C});
        visited[R][C] = true;

        while (!queue.isEmpty()) {
            int[] curr = queue.poll();
            // 出队列时进行判断是否符合条件可以结束 BFS
            if (curr[0] == 0 || curr[0] == rows - 1 || curr[1] == 0 || curr[1] == cols - 1) {
                return "YES";
            }

            // 利用 方向数组 进行 BFS 遍历
            for (int[] dir : DIRS) {
                int nextX = curr[0] + dir[0];
                int nextY = curr[1] + dir[1];
                // 如果 超出边界 或者 不符合条件(已经放问过等)则跳过该位置
                if (nextX < 0 || nextX >= rows || nextY < 0 || nextY >= cols || visited[nextX][nextY]) {
                    continue;
                }
                if (matrix[nextX][nextY] < matrix[curr[0]][curr[1]]) {
                    // 将符合条件的位置加入到队列中等待下一轮的 BFS
                    queue.offer(new int[]{nextX, nextY});
                    visited[nextX][nextY] = true;
                }
            }
        }

        return "NO";
    }
}

/**
 * Approach 2: BFS
 * 该方法是在 进队列 的时候判断是否可以结束 BFS,
 * 因此对于 所有 进队列的元素都要进行条件判断才行。
 * 包括起始点(初始值),这个很容易被忘记,请务必要注意!
 * 以该题为例,如果我们没有对 起始点 进行判断是否在边界上的话,
 * 我们将其加入 Queue 之后,我们不会再对其进行判断了,这就导致我们漏掉了一个解的情况。
 * 其他部分与 Approach 1 完全相同,参考上述的注释即可。
 *
 * 相比于 出队列 时进行判断,该做法的优点在于:
 *  在进队列时直接判断是否能够结束BFS,节省了后续其他不必要的 入队 和 出队 操作。
 *  当数据量较大或者较为特殊时,可以节省不少时间。
 *  应用实例可以参考:
 *  Bus Routes: https://github.com/cherryljr/LeetCode/blob/master/Bus%20Routes.java
 */
public class Solution {
    /**
     * @param matrix: the height matrix
     * @param R: the row of (R,C)
     * @param C: the columns of (R,C)
     * @return: Whether the water can flow outside
     */
    public String waterInjection(int[][] matrix, int R, int C) {
        int rows = matrix.length, cols = matrix[0].length;
        // 判断起始点是否符合条件,如果在边界上可以直接 return 无需 BFS
        if (R == 0 || R == rows - 1 || C == 0 || C == cols - 1) {
            return "YES";
        }

        final int[][] DIRS = new int[][]{{0, -1}, {0, 1}, {-1, 0}, {1, 0}};
        Queue<int[]> queue = new LinkedList<>();
        boolean[][] visited = new boolean[rows][cols];
        queue.offer(new int[]{R, C});
        visited[R][C] = true;

        while (!queue.isEmpty()) {
            int[] curr = queue.poll();
            for (int[] dir : DIRS) {
                int nextX = curr[0] + dir[0];
                int nextY = curr[1] + dir[1];
                if (nextX < 0 || nextX >= rows || nextY < 0 || nextY >= cols || visited[nextX][nextY]) {
                    continue;
                }
                if (matrix[nextX][nextY] < matrix[curr[0]][curr[1]]) {
                    if (nextX == 0 || nextX == rows - 1 || nextY == 0 || nextY == cols - 1) {
                        return "YES";
                    }
                    queue.offer(new int[]{nextX, nextY});
                    visited[nextX][nextY] = true;
                }
            }
        }

        return "NO";
    }
}
https://www.codetd.com/article/4667879
迷宫类问题,可以用深度优先搜索或广度优先搜索。感觉题解写的都很差,这个题我认为不需要visited数组,因为水的流动决定了它不会走回头路。
这个递归方法已经非常快了。
class Solution {
public:
    string waterInjection(vector<vector<int>> &matrix, int R, int C) {
        if (R==0 || C==0 ||R==matrix.size()-1||C==matrix[0].size()-1) return "YES";
        string up,down,right,left; 
        up=down=right=left="NO";
        if (matrix[R-1][C]<matrix[R][C]) left= waterInjection(matrix,R-1,C);
        if (matrix[R+1][C]<matrix[R][C]) right= waterInjection(matrix,R+1,C);
        if (matrix[R][C+1]<matrix[R][C]) down= waterInjection(matrix,R,C+1);
        if (matrix[R][C-1]<matrix[R][C]) up= waterInjection(matrix,R,C-1);
        if (left=="YES"||right=="YES"||up=="YES"||down=="YES") return "YES";
        else return "NO";
    }
};
非递归,使用队列,也很快:
class Solution {
public:
    string waterInjection(vector<vector<int>> &matrix, int R, int C) {
        if (R==0 || C==0 ||R==matrix.size()-1||C==matrix[0].size()-1) return "YES";
        queue<pair<int,int>> flow;
        flow.push(make_pair(R,C));
        while (!flow.empty())
       {
            pair<int,int> now=flow.front();
            flow.pop();
            if (matrix[now.first-1][now.second]<matrix[now.first][now.second]) 
               if (now.first-1==0 || now.second==0 ||now.first-1==matrix.size()-1||now.second==matrix[0].size()-1) return "YES";
               else flow.push(make_pair(now.first-1,now.second));
            if (matrix[now.first+1][now.second]<matrix[now.first][now.second]) 
               if (now.first+1==0 || now.second==0 ||now.first+1==matrix.size()-1||now.second==matrix[0].size()-1) return "YES";
               else flow.push(make_pair(now.first+1,now.second));
            if (matrix[now.first][now.second-1]<matrix[now.first][now.second]) 
               if (now.first==0 || now.second-1==0 ||now.first==matrix.size()-1||now.second-1==matrix[0].size()-1) return "YES";
               else flow.push(make_pair(now.first,now.second-1));
            if (matrix[now.first][now.second+1]<matrix[now.first][now.second]) 
               if (now.first==0 || now.second+1==0 ||now.first==matrix.size()-1||now.second+1==matrix[0].size()-1) return "YES";
               else flow.push(make_pair(now.first,now.second+1));
       }
       return "NO";
    }

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts