Thursday, October 20, 2016

[Leetcode] 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).
Analysis:
Initially, I was trying to iterate all position, and for each position (i,j) use DFS to see whether it can reach both Atlantic and Pacific but unfortunately it is TLE. For each position, the worst case is to visit all node of the matrix and takes O(m*n) time. So for total m*n node it takes O((m*n)^2).

If we think the problem the other way, if a position (i,j) can reach both Pacific and Atlantic, it mean there must be Pacific position (pi, pj) and Atlantic (ai, ai) which connect to (i, j). In another word, (i, j) must be in the DFS/BFS search path beginning from (pi, pj) and (ai, aj). So, if we can find all the node which can be reached from Pacific edge (row or column is 0) and Atlantic (row or column is maximum), these node are the position where water can flow to both the Pacific and Atlantic ocean.


void dfs(int[][] matrix, boolean[][] visited, int pre, int x, int y) {
        if (x < 0 || x >= matrix.length || y <0 || y >= matrix[0].length || visited[x][y] ||  matrix[x][y] < pre)
            return;
        
        visited[x][y] = true;

        dfs(matrix, visited, matrix[x][y], x-1, y);
        dfs(matrix, visited, matrix[x][y], x+1, y);
        dfs(matrix, visited, matrix[x][y], x, y-1);
        dfs(matrix, visited, matrix[x][y], x, y+1);

    }
    
    public List<int[]> pacificAtlantic(int[][] matrix) {
        List<int[]> list = new ArrayList<>();
        if (matrix.length == 0)
            return list;
        int m = matrix.length; 
        int n = matrix[0].length;
        
        boolean[][] dp1 = new boolean[m][n];
        boolean[][] dp2 = new boolean[m][n];
        for(int i=0; i<m; i++) {
            //Pacific
            dfs(matrix, dp1, Integer.MIN_VALUE, i, 0);
            //Atlantic
            dfs(matrix, dp2, Integer.MIN_VALUE, i, n-1);
        }
        
        for(int i=0; i<n; i++) {
            dfs(matrix, dp1, Integer.MIN_VALUE, 0, i);
            dfs(matrix, dp2, Integer.MIN_VALUE, m-1, i);
        }
    
        for(int i=0; i<m; i++) {
            for(int j=0; j<n; j++) {
                if (dp1[i][j] && dp2[i][j]) {
                    int[] pos = {i,j};
                    list.add(pos);
                }
            }
        }
    
        
        return list;
    }

[Leetcode] Battleships in a Board

Given an 2D board, count how many different battleships are in it. The battleships are represented with 'X's, empty slots are represented with '.'s. You may assume the following rules:
  • You receive a valid board, made of only battleships or empty slots.
  • Battleships can only be placed horizontally or vertically. In other words, they can only be made of the shape 1xN (1 row, N columns) or Nx1 (N rows, 1 column), where N can be of any size.
  • At least one horizontal or vertical cell separates between two battleships - there are no adjacent battleships.
Example:
X..X
...X
...X
In the above board there are 2 battleships.
Invalid Example:
...X
XXXX
...X
This is not a valid board - as battleships will always have a cell separating between them.
Your algorithm should not modify the value of the board.
Analysis:
At the very first glance, it looks like a BFS/DFS to find the group of connected nodes. But it has the limit that all the battleships have to be in the same row or column. In addition, it has the limit that the board cannot be changed, which means you cannot mark the board as visited or not.

Given that the battleship must be in the same row or column, we can simply check all rows and columns and count it if it is a valid battleship. For each row, we need to collect the number of battleships, which is nothing but the same as finding the number of word separated by space. Notice that you need to check whether the battleship is valid or not by checking whether it has upper or down row battleship connected. Similarly we can get the battleships for the columns, except that for the battleship occupying only one space which has been collected by the row already, so no need to recollected.

Comparing to other solutions, this solution is able to take care of the invalid board as well. 


    int getColCount(char[][] board, int k) {
        int m = board.length;
        int n = board[0].length;
        int i = 0;
        int count = 0;
        while(i < m) {
            while(i < m && board[i][k] == '.')
                i++;

            boolean valid = true;
            int c = 0;
            while(i < m && board[i][k] == 'X') {
                if ((k > 0 && board[i][k-1] == 'X') || (k < n-1 && board[i][k+1] == 'X'))
                    valid = false;
                i++;
                c++;
            }
            //exclude the single node
            if (valid && c > 1)
                count++;
        }
        
        return count;
    }
    
    
    int getRowCount(char[][] board, int k) {
        int m = board.length;
        int n = board[0].length;
        int i = 0;
        int count = 0;
        while(i < n) {
            while(i <n && board[k][i] == '.')
                i++;

            boolean valid = true;
            int c = 0;
            while(i <n && board[k][i] == 'X') {
                if ((k > 0 && board[k-1][i] == 'X') || (k < m-1 && board[k+1][i] == 'X'))
                    valid = false;
                i++;
                c++;
            }
            if (valid && c > 0)
                count++;
        }
        
        return count;
    }
    
    public int countBattleships(char[][] board) {
        int count = 0;
        if (board.length == 0)
            return 0;
            
        for(int i=0; i<board.length; i++)
            count+= getRowCount(board, i);

        for(int i=0; i<board[0].length; i++)
            count+= getColCount(board, i);        
        
        return count;
    }

Wednesday, October 19, 2016

[Leetcode] Longest Repeating Character Replacement

Given a string that consists of only uppercase English letters, you can replace any letter in the string with another letter at most k times. Find the length of a longest substring containing all repeating letters you can get after performing the above operations.
Note:
Both the string's length and k will not exceed 104.
Example 1:
Input:
s = "ABAB", k = 2

Output:
4

Explanation:
Replace the two 'A's with two 'B's or vice versa.
Example 2:
Input:
s = "AABABBA", k = 1

Output:
4

Explanation:
Replace the one 'A' in the middle with 'B' and form "AABBBBA".
The substring "BBBB" has the longest repeating letters, which is 4.
Analysis:
The basic idea is to iterate all substring which could satisfy the condition.  That is, the substring would become repeating character string if k characters were replaced. If we have count of all substring characters, we know that the maximum number of characters to be replaced = the total number of characters - the max number of any single letter. It would takes O (n^2 * k) time.

We can improve the performance. Notice that if substring(i, j) is a repeating character string and substring(i, j+1) is not, then all substring(i, j+n) will not be a repeating character as well. So we have to increase the i to have another repeating character substring. It is actual a slide window and takes O(n*k) time. 

    int getCount(Map<Character, Integer> m, int k) {
        
        int maxVal = 0;
        int total = 0;
        
        for(Character c: m.keySet()) {
            total += m.get(c);
            maxVal = Math.max(maxVal, m.get(c));
        }

        if (total - maxVal > k)
            return -1;
        
        return total;
    }
    public int characterReplacement(String s, int k) {
        int ret = 0;
        int i = 0;
        int j = 0;

        Map<Character, Integer> m = new HashMap<>();
        while(j < s.length()) {
            m.put(s.charAt(j), m.getOrDefault(s.charAt(j), 0) + 1);
            int count = getCount(m, k);
            //if not satisfied, shrink the windows by increasing i
            if (count < 0) {
                while(i < j && count < 0) {
                    m.put(s.charAt(i), m.get(s.charAt(i)) - 1);
                    count = getCount(m, k);
                    i++;
                }
            }
            ret = Math.max(ret, count);
            j++;
        }
        
        return ret;
    }

Tuesday, January 20, 2015

[Leetcode] Find Peak Element

A peak element is an element that is greater than its neighbors.
Given an input array where num[i] ≠ num[i+1], find a peak element and return its index.
The array may contain multiple peaks, in that case return the index to any one of the peaks is fine.
You may imagine that num[-1] = num[n] = -∞.
For example, in array [1, 2, 3, 1], 3 is a peak element and your function should return the index number 2.
Analysis:
Pretty strait forward. Given num[-1] = num[n] = -∞ and num[i] ≠ num[i+1], if num[0] is greater than num[1], num[0] will be the peak since num[0] > num[1] and num[0] > num[-1]. If not, then num[1] could be the peak if num[1] > num[2], which could be computed in the next loop.  



    int findPeakElement(const vector &num) {
        if (num.size() == 1)
            return 0;
        int peak = 0;
        for(int i=1; i < num.size(); i++)
        {
            if (num[i] < num[peak])
                return i-1;
            else
                peak = i;
        }
        
        return peak;
    }

Monday, January 19, 2015

[Leetcode] Dungeon Game

The demons had captured the princess (P) and imprisoned her in the bottom-right corner of a dungeon. The dungeon consists of M x N rooms laid out in a 2D grid. Our valiant knight (K) was initially positioned in the top-left room and must fight his way through the dungeon to rescue the princess.
The knight has an initial health point represented by a positive integer. If at any point his health point drops to 0 or below, he dies immediately.
Some of the rooms are guarded by demons, so the knight loses health (negative integers) upon entering these rooms; other rooms are either empty (0's) or contain magic orbs that increase the knight's health (positive integers).
In order to reach the princess as quickly as possible, the knight decides to move only rightward or downward in each step.

Write a function to determine the knight's minimum initial health so that he is able to rescue the princess.
For example, given the dungeon below, the initial health of the knight must be at least 7 if he follows the optimal path RIGHT-> RIGHT -> DOWN -> DOWN.
-2 (K)-33
-5-101
1030-5 (P)

Notes:
  • The knight's health has no upper bound.
  • Any room can contain threats or power-ups, even the first room the knight enters and the bottom-right room where the princess is imprisoned.
Analysis:
It is easy to know that at grid P, since " at any point his health point drops to 0 or below, he dies immediately", the remaining health value should be at least 1,  that is, initialHealth + dungeon >= 1, we have initialHealth = max(1, 1 - dungeon[i][j]).  (Notice, at any grid, the initial health should be at least 1 (for example,  test case [1,0,0] require initial health 1 even though it has positive remaining health at grid[0][1] and grid[0][2])
Similarly, to satisfy the initial health of dungeon[i][j], the initial health of dungeon[i-1][j] (or dungeon[i][j-1]) should be at least initialHealth[i-1][j] + dungeon[i-1][j] = initialHealth[i][j], that is, initialHealth[i][j] = initialHealth[i][j] - dungeon[i-1][j]. 
In addition, if grid[i][j] can go both grid[i+1][j] and grid[i][j+1] to P,  we should choose a path with less initial health between grid[i+1][j] and grid[i][j+1] since it require less initial health of grid[i][j].
We can simply code the solution by having the dynamic programming equations. 



         int calculateMinimumHP(vector &dungeon) {
        int m = dungeon.size();
        int n = dungeon[0].size();
        vector minInitHealth(m, vector<int>(n,0));
        for(int i=m-1; i>=0; i--)
        {
            for (int j=n-1; j>=0; j--)
            {
                if (i == m-1 && j == n-1)
                {
                    minInitHealth[i][j] = max(1, 1 - dungeon[i][j]);
                }  
                else if (i == m-1)
                {
                    minInitHealth[i][j] = max(1, minInitHealth[i][j+1] - dungeon[i][j]);
                }  
                else if (j == n-1)
                {
                    minInitHealth[i][j] = max(1, minInitHealth[i+1][j] - dungeon[i][j]);
                }  
                else
                {
                    minInitHealth[i][j] = max(1, min(minInitHealth[i+1][j],minInitHealth[i][j+1]) - dungeon[i][j]);
                }  
            }
        }
        
        return  minInitHealth[0][0];
    }

Sunday, January 18, 2015

[Leetcode] Excel Sheet Column Title

Given a positive integer, return its corresponding column title as appear in an Excel sheet.
For example:
    1 -> A
    2 -> B
    3 -> C
    ...
    26 -> Z
    27 -> AA
    28 -> AB 
Analysis:
Similar to the problem of "Excel Sheet Column Number", we want to represent a number with 26 as base. The code is almost exactly same as converting a decimal number to string, eg: 1234 -> "1234", except that it is 26 base and beginning from 1 rather than 0 (decimal begins from 0 as 0-9). 


    string convertToTitle(int n) {
        string str = "";
        int k = 26;
        while(n > 0)
        {
            str.insert(str.begin(), (n - 1) % k + 'A');
            n = (n - 1) / k;
        }
        
        return str;
    }

[Leetcode] Excel Sheet Column Number

Given a column title as appear in an Excel sheet, return its corresponding column number.
For example:
    A -> 1
    B -> 2
    C -> 3
    ...
    Z -> 26
    AA -> 27
    AB -> 28 

Analysis:

We know a number could be represented as binary, octal, decimal or hexadecimal. So what if we want to represent a number with 26 as base? We could represent 1 as A, 2 as B and Z as 26 which is exactly how an Excel column title works. 

It is pretty strait forward to convert a decimal represented string to a number, eg "123" = 1*100 + 2*10 + 3. Well, it is almost exactly the same for 26 based number as well, as the following code shows. 




    int titleToNumber(string s) {
        int n = 0;
        int k = 26;
        for(int i=0; i < s.size();i++)
        {
            n = n * k + (s[i] - 'A' + 1);
        }
        return n;
    }