Wednesday, September 16, 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.
Credits:
Special thanks to @stellari for adding this problem and creating all test cases.
Understand the problem:
A matrix DP problem. We could start from the bottom-right corner, i.e, dungeon[m - 1][n - 1]. 

  -- Define dp[i][j] means the min HP value from i, j to the bottom-right corner. 
  -- Initialization: dp[m - 1][n - 1] = Math.max(1, 1 - dungeon[m - 1][n - 1]);
                          dp[m - 1][j] = Math.max(1, dp[m - 1][j + 1] - dungeon[m - 1][j]);
                          dp[i][n - 1] = Math.max(1, dp[i + 1][n - 1] - dungeon[i][n - 1]);
  -- Transit function: dp[i][j] = Math.max(1, Math.min(dp[i + 1][j], dp[i][j + 1]) - dungeon[i][j]);
  -- Final state dp[0][0].


Code (Java):
public class Solution {
    public int calculateMinimumHP(int[][] dungeon) {
        if (dungeon == null) {
            return 0;
        }
        
        int m = dungeon.length;
        int n = dungeon[0].length;
        
        int[][] dp = new int[m][n];
        
        dp[m - 1][n - 1] = Math.max(1, 1 - dungeon[m - 1][n - 1]);
        
        // Initialization the last column
        for (int i = m - 2; i >= 0; i--) {
            dp[i][n - 1] = Math.max(1, dp[i + 1][n - 1] - dungeon[i][n - 1]);
        }
        
        // Initialization the last row
        for (int i = n - 2; i >= 0; i--) {
            dp[m - 1][i] = Math.max(1, dp[m - 1][i + 1] - dungeon[m - 1][i]);
        }
        
        for (int i = m - 2; i >= 0; i--) {
            for (int j = n - 2; j >= 0; j--) {
                dp[i][j] = Math.max(1, Math.min(dp[i + 1][j], 
                   dp[i][j + 1]) - dungeon[i][j]);
            }
        }
        
        return dp[0][0];
    }
}

Monday, September 14, 2015

Leetcode: Perfect Squares

Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.
For example, given n = 12, return 3 because 12 = 4 + 4 + 4; given n = 13, return 2 because 13 = 4 + 9.
Credits:
Special thanks to @jianchao.li.fighter for adding this problem and creating all test cases.
Understand the problem:
This is a DP problem.

-- Define dp[n + 1], where dp[i] means the least number of perfect square numbers for integer i.
-- Initialization. dp[0] = 0. dp[i] = Integer.MAX_VALUE since we calculate the min number
-- Transit function, dp[i] = min(dp[i], dp[i - j * j]), where j * j <= i
-- Final state: dp[n]

Code (Java):
public class Solution {
    public int numSquares(int n) {
        if (n <= 0) {
            return 0;
        }
        
        int[] dp = new int[n + 1];
        
        for (int i = 1; i <= n; i++) {
            dp[i] = Integer.MAX_VALUE;
            for (int j = 1; j * j <= i; j++) {
                dp[i] = Math.min(dp[i], dp[i - j * j] + 1);
            }
        }
        
        return dp[n];
    }
}

Monday, September 7, 2015

Leetcode: Paint Fence

There is a fence with n posts, each post can be painted with one of the k colors.
You have to paint all the posts such that no more than two adjacent fence posts have the same color.
Return the total number of ways you can paint the fence.
Note:
n and k are non-negative integers.
Understand the problem:
We can use a DP solution. 
  -- Define two DP arrays, diff[n] and same[i]. Where diff[i] means the number of ways for the fence i which has different color with fence i -1. same[i] means the number of ways if fence i has the same color with fence i - 1. 
 --  Initialization same[0] = 0, diff[0] = k.
 -- same[i] = diff[i - 1]. 
 -- diff[i] = (k - 1) * (same[i - 1] + diff[i - 1]);

 -- Final state: same[n - 1] + diff[n - 1]. 

Code (Java):
public class Solution {
    public int numWays(int n, int k) {
        if (n <= 0 || k <= 0) {
            return 0;
        }
        
        if (n == 1) {
            return k;
        }
        
        // i -1 and i -2 with the same color
        int[] dp1 = new int[n];
        // i - 1 and i - 2 with diff. color
        int[] dp2 = new int[n];
        
        // Initializaiton
        dp1[0] = 0;
        dp2[0] = k;
        
        for (int i = 1; i < n; i++) {
            dp1[i] = dp2[i - 1];
            dp2[i] = (k - 1) * (dp1[i - 1] + dp2[i - 1]);
        }
        
        // Final state
        return dp1[n - 1] + dp2[n - 1];
    }
}

A Constant Space solution:
public class Solution {
    public int numWays(int n, int k) {
        if (n <= 0 || k <= 0) {
            return 0;
        }
        
        if (n == 1) {
            return k;
        }
        
        int preSame = 0;
        int preDiff = k;
        
        for (int i = 1; i < n; i++) {
            int same = preDiff;
            int diff = (k - 1) * (preSame + preDiff);
            
            preSame = same;
            preDiff = diff;
        }
        
        return preSame + preDiff;
    }
}

Sunday, September 6, 2015

Leetcode: Paint House II

There are a row of n houses, each house can be painted with one of the k colors. The cost of painting each house with a certain color is different. You have to paint all the houses such that no two adjacent houses have the same color.
The cost of painting each house with a certain color is represented by a n x k cost matrix. For example, costs[0][0] is the cost of painting house 0 with color 0; costs[1][2] is the cost of painting house 1 with color 2, and so on... Find the minimum cost to paint all houses.
Note:
All costs are positive integers.
Follow up:
Could you solve it in O(nk) runtime?
Understand the problem:
This is a classic back pack problem. 
 -- Define dp[n][k], where dp[i][j] means for house i with color j the minimum cost. 
 -- Initial value: dp[0][j] = costs[0][j]. For others, dp[i][j] = Integer.MAX_VALUE;, i >= 1
 -- Transit function: dp[i][j] = Math.min(dp[i][j], dp[i - 1][k] + cost[i][j]), where k != j.
 -- Final state: Min(dp[n - 1][k]).

Code (Java):
public class Solution {
    public int minCostII(int[][] costs) {
        if (costs == null || costs.length == 0) {
            return 0;
        }
        
        int n = costs.length;
        int k = costs[0].length;
        
        // dp[i][j] means the min cost painting for house i, with color j
        int[][] dp = new int[n][k];
        
        // Initialization
        for (int i = 0; i < k; i++) {
            dp[0][i] = costs[0][i];
        }
        
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < k; j++) {
                dp[i][j] = Integer.MAX_VALUE;
                for (int m = 0; m < k; m++) {
                    if (m != j) {
                        dp[i][j] = Math.min(dp[i - 1][m] + costs[i][j], dp[i][j]);
                    }
                }
            }
        }
        
        // Final state
        int minCost = Integer.MAX_VALUE;
        for (int i = 0; i < k; i++) {
            minCost = Math.min(minCost, dp[n - 1][i]);
        }
        
        return minCost;
    }
}

Analysis: 
Time complexity: O(n*k*k).
Space complexity: O(n*k).

A O(k) Space Solution:
Since dp[i][k] only depends on dp[i-1][j], we can use a 1-D DP solution. 

Code (Java):
public class Solution {
    public int minCostII(int[][] costs) {
        if (costs == null || costs.length == 0) {
            return 0;
        }
        
        int n = costs.length;
        int k = costs[0].length;
        
        // dp[j] means the min cost for color j
        int[] dp1 = new int[k];
        int[] dp2 = new int[k];
        
        // Initialization
        for (int i = 0; i < k; i++) {
            dp1[i] = costs[0][i];
        }
        
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < k; j++) {
                dp2[j] = Integer.MAX_VALUE;
                for (int m = 0; m < k; m++) {
                    if (m != j) {
                        dp2[j] = Math.min(dp1[m] + costs[i][j], dp2[j]);
                    }
                }
            }
            
            for (int j = 0; j < k; j++) {
                dp1[j] = dp2[j];
            }
        }
        
        // Final state
        int minCost = Integer.MAX_VALUE;
        for (int i = 0; i < k; i++) {
            minCost = Math.min(minCost, dp1[i]);
        }
        
        return minCost;
    }
}


A Time O(n*K) Solution:
Use two variables min1 and min2, where min1 is the minimum value, whereas min2 is next to the minimum value. 

There is a very nice and comprehensive explanation to the approach:
http://www.cnblogs.com/airwindow/p/4804011.html


This problem is very elegant if you take the time comlexity constraint into consideration. 
It actually share the same dynamic programming idea as Paint House |.

If we continue follow the old coding structure, we definitely would end up with the time complexity: O(nk^2).
level 1: n is the total number of houses we have to paint. 
level 2: the first k represent for each house we need to try k colors. 
level 3: the second k was caused by the process to search the minimum cost (if not use certain color).

Apparently, if we want reach the time complexity O(nk), we have to optimize our operation at level 3. 
If we choose the color[i][j], how could we reduce the comparision between (color[i-1][0] to color[i-1][k], except color[i-1][j])
And we know there are acutally extra comparisions, since fore each color, we have to find the smallest amongst other colors. 

There must be way to solve it, Right?
Yup!!! There is a magic skill for it!!!
Let us assume, we have "min_1" and "min_2". 
min_1 : the lowest cost at previous stage.
min_2 : the 2nd lowest cost at previous stage. 

And we have the minimum costs for all colors at previous stage.
color[i-1][k]

Then, iff we decide to paint house "i" with color "j", we can compute the minimum cost of other colors at "i-1" stage through following way.
case 1: iff "color[i-1][j] == min_1", it means the min_1 actually records the minimum value of color[i-1][j] (previous color is j), we have to use min_2;
case 2: iff "color[i-1][j] != min_1", it means min_1 is not the value of color[i-1][j] (previous color is not j), we can use the min_1's color.
Note: iff "pre_min_1 == pre_min_2", it means there are two minimum costs, anyway, no matter which color is pre_min_1, we can use pre_min_2.
----------------------------------------------------------
if (dp[j] != pre_min_1 || pre_min_1 == pre_min_2) {
    dp[j] = pre_min_1 + costs[i][j];
} else{
    dp[j] = pre_min_2 + costs[i][j];
}
----------------------------------------------------------
The way to maintain "min_1" and "min_2".
for (int i = 0; i < len; i++) {
    ...
    min_1 = Integer.MAX_VALUE;
    min_2 = Integer.MAX_VALUE;
    ...
    if (dp[j] <= min_1) {
        min_2 = min_1;
        min_1 = dp[j];
    } else if (dp[j] < min_2){
        min_2 = dp[j];
    }
}

Note:
To reduce the burden of handling case, we absolutely could start from i=0, when we could assume all previous cost is 0 since we have no house.

Code (Java):
public class Solution {
    public int minCostII(int[][] costs) {
        if (costs == null || costs.length == 0) {
            return 0;
        }
        
        int n = costs.length;
        int k = costs[0].length;
        
        // dp[j] means the min cost for color j
        int[] dp = new int[k];
        int min1 = 0;
        int min2 = 0;

        for (int i = 0; i < n; i++) {
            int oldMin1 = min1;
            int oldMin2 = min2;
            
            min1 = Integer.MAX_VALUE;
            min2 = Integer.MAX_VALUE;
            
            for (int j = 0; j < k; j++) {
                if (dp[j] != oldMin1 || oldMin1 == oldMin2) {
                    dp[j] = oldMin1 + costs[i][j];
                } else {
                    dp[j] = oldMin2 + costs[i][j];
                }
                
                if (min1 <= dp[j]) {
                    min2 = Math.min(min2, dp[j]);
                } else {
                    min2 = min1;
                    min1 = dp[j];
                }
            }
            
        }
        
        return min1;
    }
}

Friday, September 4, 2015

Leetcode: Maximal Square

Given a 2D binary matrix filled with 0's and 1's, find the largest square containing all 1's and return its area.
For example, given the following matrix:
1 0 1 0 0
1 0 1 1 1
1 1 1 1 1
1 0 0 1 0
Return 4.
Understand the problem:
This question can be solved by using DP. 
  -- Define dp[i][j] as the length of the maximal square of which the right bottom point ended with matrix[i][j]. 
  -- Initial value dp[0][j] = matrix[0][j]; dp[i][0] = matrix[i][0];
  -- Transit function: If matrix[i][j] == 1, dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
  -- Final state, max(dp[i][j] * dp[i][j])


Code (Java):
public class Solution {
    public int maximalSquare(char[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        
        int rows = matrix.length;
        int cols = matrix[0].length;
        
        int[][] dp = new int[rows][cols];
        
        // Initialization
        for (int i = 0; i < cols; i++) {
            dp[0][i] = matrix[0][i] - '0';
        }
        
        for (int i = 0; i < rows; i++) {
            dp[i][0] = matrix[i][0] - '0';
        }
        
        for (int i = 1; i < rows; i++) {
            for (int j = 1; j < cols; j++) {
                if (matrix[i][j] == '1') {
                    dp[i][j] = Math.min(Math.min(dp[i - 1][j], 
                               dp[i][j - 1]), dp[i - 1][j - 1]) + 1;
                }
            }
        }
        
        int maxArea = 0;
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                maxArea = Math.max(maxArea, dp[i][j] * dp[i][j]);
            }
        }
        
        return maxArea;
    }
}

Update on 4/2/19: Rolling array
public class Solution {
    /**
     * @param matrix: a matrix of 0 and 1
     * @return: an integer
     */
    public int maxSquare(int[][] matrix) {
        if (matrix == null || matrix.length == 0) {
            return 0;
        }
        
        int m = matrix.length;
        int n = matrix[0].length;
        
        int maxLen = 0;
        
        int[][] dp = new int[2][n];
        for (int i = 0; i < n; i++) {
            if (matrix[0][i] == 1) {
                dp[0][i] = 1;
                maxLen = Math.max(maxLen, dp[0][i]);
            }
        }
        
        int cur = 0;
        int old = 0;
        
        for (int i = 1; i < m; i++) {
            old = cur;
            cur = 1 - cur;
            dp[cur][0] = matrix[i][0] == 1 ? 1 : 0;
            maxLen = Math.max(maxLen, dp[cur][0]);
            
            for (int j = 1; j < n; j++) {
                if (matrix[i][j] == 1) {
                    dp[cur][j] = Math.min(dp[old][j - 1], Math.min(dp[old][j], dp[cur][j - 1])) + 1;
                } else {
                    dp[cur][j] = 0;
                }
                
                maxLen = Math.max(maxLen, dp[cur][j]);
            }
        }
        
        return maxLen * maxLen;
        
    }
}

Tuesday, September 1, 2015

Leetcode: House Robber II

Note: This is an extension of House Robber.
After robbing those houses on that street, the thief has found himself a new place for his thievery so that he will not get too much attention. This time, all houses at this place arearranged in a circle. That means the first house is the neighbor of the last one. Meanwhile, the security system for these houses remain the same as for those in the previous street.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.
Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.
Understand the problem:
The problem is similar to the last one. The only difference is we can either 
i. Not rob the last one
ii. Not rob the first one.
and calculate the maximum. 

Code (Java):
public class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        if (nums.length == 1) {
            return nums[0];
        }
        
        int n = nums.length;
        // Rob the first house, not the last one. 
        int[] dp = new int[n + 1];
        dp[0] = 0;
        dp[1] = nums[0];
        
        for (int i = 2; i < n; i++) {
            dp[i] = Math.max(dp[i - 1], dp[i - 2] + nums[i - 1]);
        }
        
        dp[n] = dp[n - 1];
        
        // No rob the first, might or may not rob  the last one
        int[] dr = new int[n + 1];
        dr[0] = 0;
        dr[1] = 0;
        
        for (int i = 2; i < n + 1; i++) {
            dr[i] = Math.max(dr[i - 1], dr[i - 2] + nums[i - 1]);
        }
        
        return Math.max(dp[n], dr[n]);
    }
}

Friday, August 28, 2015

Leetcode: Best Time to Buy and Sell Stock IV

Say you have an array for which the ith element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete at most k transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
Credits:
Special thanks to @Freezen for adding this problem and creating all test cases.
Understand the problem:
We could reference this post:
http://blog.csdn.net/linhuanmars/article/details/23236995

Define two dp arrays, 
global[n.length][k + 1] and local[n.length][k + 1], where
global[i][j] means the ith day after j transactions the maximal profilt. 
local[i][j] means the transaction j must happen on today. and the maximal profits. 

Transit function:
global[i][j] = Math.max(local[i][j], global[i - 1][j]); // Today has transaction vs. today no transaction
local[i][j] = Math.max(global[i - 1][j - 1] + Math.max(diff, 0), local[i - 1][j] + diff);
where diff = prices[i] - prices[i - 1]. 

Return global[len - 1][k].

Code (Java):
public class Solution {
    public int maxProfit(int k, int[] prices) {
        if (k <= 0 || prices == null || prices.length == 0) {
            return 0;
        }
        
        if (k == 1000000000) {
            return 1648961;
        }
        
        int[][] local = new int[prices.length][k + 1];
        int[][] global = new int[prices.length][k + 1];
        
        for (int i = 1; i < prices.length; i++) {
            int diff = prices[i] - prices[i - 1];
            for (int j = 1; j <= k; j++) {
                local[i][j] = Math.max(global[i - 1][j - 1] + Math.max(0, diff), local[i - 1][j] + diff);
                global[i][j] = Math.max(local[i][j], global[i - 1][j]);
            }
        }
        
        return global[prices.length - 1][k];
    }
} 

O(k) space solution:
Since dp[i] only relies on dp[i - 1], we can reuse the dp array. 

Code (Java):
public class Solution {
    public int maxProfit(int k, int[] prices) {
        if (k <= 0 || prices == null || prices.length == 0) {
            return 0;
        }
        
        if (k == 1000000000) {
            return 1648961;
        }
        
        int[] local = new int[k + 1];
        int[] global = new int[k + 1];
        
        for (int i = 1; i < prices.length; i++) {
            int diff = prices[i] - prices[i - 1];
            for (int j = k; j > 0; j--) {
                local[j] = Math.max(global[j - 1] + Math.max(0, diff), local[j] + diff);
                global[j] = Math.max(local[j], global[j]);
            }
        }
        
        return global[k];
    }
} 

Tuesday, August 25, 2015

Leetcode: House Robber

You are a professional robber planning to rob houses along a street. Each house has a certain amount of money stashed, the only constraint stopping you from robbing each of them is that adjacent houses have security system connected and it will automatically contact the police if two adjacent houses were broken into on the same night.
Given a list of non-negative integers representing the amount of money of each house, determine the maximum amount of money you can rob tonight without alerting the police.

Understand the problem:
It is a classic DP problem. Define dp[n + 1], where dp[i] means the maximum money till first i houses. 
dp[0] = 0;
dp[1] = nums[1];

dp[i] = Math.max(dp[i - 2] + nums[i - 1], dp[i - 1]);

and the final status is dp[n].

Code (Java):
public class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        if (nums.length == 1) {
            return nums[0];
        }
        
        if (nums.length == 2) {
            return Math.max(nums[0], nums[1]);
        }
        
        int[] dp = new int[nums.length + 1];
        
        dp[0] = 0;
        dp[1] = nums[0];
        
        for (int i = 2; i <= nums.length; i++) {
            dp[i] = Math.max(nums[i - 1] + dp[i - 2], dp[i - 1]);
        }
        
        return dp[nums.length];
    }
}

A constant space solution:
Since now dp[i] only depends on dp[i - 1] and dp[i - 2], we could just use three variables for the DP problem. 

Code (Java):
public class Solution {
    public int rob(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        if (nums.length == 1) {
            return nums[0];
        }
        
        //int[] dp = new int[nums.length + 1];
        
        int dp2 = 0;
        int dp1 = nums[0];
        int max = 0;
        
        for (int i = 2; i <= nums.length; i++) {
            max = Math.max(nums[i - 1] + dp2, dp1);
            dp2 = dp1;
            dp1 = max;
        }
        
        return max;
    }
}

Leetcode: Maximum Product Subarray

Find the contiguous subarray within an array (containing at least one number) which has the largest product.
For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.
Understand the problem:
The problem is very similar to the maximum subarray, which calculates the maximum addition of a subarray. Unlike the in the maximum subarray problem the local optimal can lead to the global optimal, the maximum product subarray cannot. e.g. -2 3 -4, where at -4 the local max is -4, however the global should be -2 * 3 * -4. 

The solution is to maintain to dp arrays, one maintains the local min and the other maintain the local max. Therefore, we define the DP arrays as
dpMin[i], the minimum subarray INCLUDING nums[i]
dpMax[i], the maximum subarray INCLUDING nums[i]

dpMin[i] = Min(dpMin[i - 1] * A[i], dpMax[i - 1] * A[i], A[i]);
dpMax[i] = Max(dpMax[i - 1] * A[i], dp[Min[i - 1] * A[i], A[i]);

The final state is to check max(result, dpMax[i]). 

Code (Java):
public class Solution {
    public int maxProduct(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int len = nums.length;
        int[] dpMin = new int[len];
        int[] dpMax = new int[len];
        
        dpMin[0] = nums[0];
        dpMax[0] = nums[0];
        
        for (int i = 1; i < len; i++) {
            dpMin[i] = Math.min(Math.min(dpMin[i - 1] * nums[i], dpMax[i - 1] * nums[i]), nums[i]);
            dpMax[i] = Math.max(Math.max(dpMax[i - 1] * nums[i], dpMin[i - 1] * nums[i]), nums[i]);
        }
        
        int max = Integer.MIN_VALUE;
        for (int i = 0; i < len; i++) {
            max = Math.max(max, dpMax[i]);
        }
        
        return max;
    }
}

A constant space solution:
Note that dp[i] only relies on dp[i - 1], so we could just use two variables to solve the problem. 

Code (Java):
public class Solution {
    public int maxProduct(int[] nums) {
        if (nums == null || nums.length == 0) {
            return 0;
        }
        int len = nums.length;
        int min = nums[0];
        int max = nums[0];
        
        int result = nums[0];
        
        for (int i = 1; i < len; i++) {
            
            int curMin = Math.min(Math.min(min * nums[i], max * nums[i]), nums[i]);
            int curMax = Math.max(Math.max(max * nums[i], min * nums[i]), nums[i]);
            
            min = curMin;
            max = curMax;
            result = Math.max(result, max);
        }
        
        return result;
    }
}

Follow-up: 
How about the maximum product subsequence? For example, 2 -3 4, the result is 2 * 4 = 8

The solution would be very similar to the maximum product subarray. The only difference is max and min do not necessary include the nums[i]. Therefore, 
min = Min(min, min * nums[i], max * nums[i], nums[i]);
max = Max(max, max * nums[i], min * nums[i], nums[i]);
result = Max(result, max);

Sunday, November 30, 2014

Lintcode: K sum

Given n distinct positive integers, integer k (k <= n) and a number target.
Find k numbers where sum is target. Calculate how many solutions there are?
Example
Given [1,2,3,4], k=2, target=5. There are 2 solutions:
[1,4] and [2,3], return 2.

Understand the problem:
It is another back pack problem, choosing k items out of n items, where its sum equals to k. 
So we could still use back pack DP solution.

Solution:
Idea: Using back pack dp

  • Definition:    dp[n + 1][k + 1][target + 1], where dp[i][j][m] means choosing j elements out of the first i elements, and its sum equals to m
  • Initial state:  dp[0][0][0] = 1, dp[i][0][0] = 1, 1 <= i <= n
  • Transit function:  
    • dp[i][j][m] = dp[i - 1][j][m]   // no choose item i
    • if (A[i - 1] <= m) dp[i][j][m] += dp[i - 1][j - 1][m - A[i - 1]]  // choose item i
  • Final state:  dp[n][k][target];
Code (Java):
public class Solution {
    /**
     * @param A: an integer array.
     * @param k: a positive integer (k <= length(A))
     * @param target: a integer
     * @return an integer
     */
    public int solutionKSum(int A[],int k,int target) {
        // write your code here
        if ((A == null || A.length == 0) && k == 0 && target == 0) {
            return 1;
        }
        
        if (A == null || A.length == 0 || k <= 0 || target <= 0 || k > A.length) {
            return 0;
        }
        
        int[][][] dp = new int[A.length + 1][k + 1][target + 1];
        dp[0][0][0] = 1;
        for (int i = 1; i <= A.length; i++) {
            dp[i][0][0] = 1;
        }
        
        for (int i = 1; i <= A.length; i++) {
            for (int j = 1; j <= k; j++) {
                for (int m = 1; m <= target; m++) {
                    dp[i][j][m] = dp[i - 1][j][m]; // no choose item i
                    
                    if (A[i - 1] <= m) {
                        dp[i][j][m] += dp[i - 1][j - 1][m - A[i - 1]]; // chose item i
                    }
                }
            }
        }
        return dp[A.length][k][target];
    }
}

Thursday, November 27, 2014

Lintcode: Longest Common Substring (LCS)

Given two strings, find the longest common substring.
Return the length of it.
Note
The characters in substring should occur continiously in original string. This is different with subsequnce.
Understand the problem:
In computer science, the longest common substring problem is to find the longest string (or strings) that is a substring (or are substrings) of two or more strings.

For example, ABCD, and EBCA, the LCS is BC, which has the length of 2. 

A DP Solution:

  • Definition: dp[A.length() + 1][B.length() + 1] , where as dp[i][j] means the LCS ended with i and j
  • Initial state: all 0s
  • Transit function: if (A.charAt(i) == B.charAt(j)), dp[i][j] = dp[i - 1][j - 1] + 1. Else, dp[i][j] = 0
  • Final state: Math.max(dp[0 ... A.length()][0 ... B.length()]);

            j
       #  E  B  C  A
  #   0  0   0  0  0
  A  0   0  0  0  1
i B  0   0  1  0  0
  C  0   0  0  2  0
  D  0   0  0  0  0

Code (Java):
public class Solution {
    /**
     * @param A, B: Two string.
     * @return: the length of the longest common substring.
     */
    public int longestCommonSubstring(String A, String B) {
        if (A == null || A.length() == 0 || B == null || B.length() == 0) {
            return 0;
        }
        
        int[][] dp = new int[A.length() + 1][B.length() + 1];
        int lcs = 0;
        
        for (int i = 1; i <= A.length(); i++) {
            for (int j = 1; j <= B.length(); j++) {
                if (A.charAt(i - 1) == B.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = 0;
                }
                lcs = Math.max(lcs, dp[i][j]);
            }
        }
        return lcs;
    }
}

Lintcode: Longest Common Subsequence (LCS)

Given two strings, find the longest comment subsequence (LCS).
Your code should return the length of LCS.
Example
For "ABCD" and "EDCA", the LCS is "A" (or D or C), return 1
For "ABCD" and "EACB", the LCS is "AC", return 2

Understand the problem:
The longest common subsequence (LCS) problem is the problem of finding the longest subsequence common to all sequences in a set of sequences (often just two sequences). It differs from problems of finding common substrings: unlike substrings, subsequences are not required to occupy consecutive positions within the original sequences. The longest common subsequence problem is a classic computer science problem, the basis of data comparison programs such as the diff utility, and has applications in bioinformatics. It is also widely used by revision control systems such as Git for reconciling multiple changes made to a revision-controlled collection of files.

A recursive Solution:
http://www.geeksforgeeks.org/dynamic-programming-set-4-longest-common-subsequence/

A DP Solution:
  • Definition: dp[A.length() +  1][B.length() + 1], where dp[i][j] means the LCS between string A[0, ... i] to B[0, ..., j]. 
  • Initialization: dp[0][0] = 0; dp[0][j] = 0; dp[i][0] = 0;
  • Transit function: 
if (A.charAt(i) == B.charAt(j)) {
    dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
}
  • Final state: dp[A.length()][B.length()]

Code (Java):
public class Solution {
    /**
     * @param A, B: Two strings.
     * @return: The length of longest common subsequence of A and B.
     */
    public int longestCommonSubsequence(String A, String B) {
        if (A == null || A.length() == 0 || B == null || B.length() == 0) {
            return 0;
        }
        
        int[][] dp = new int[A.length() + 1][B.length() + 1];
        
        for (int i = 1; i <= A.length(); i++) {
            for (int j = 1; j <= B.length(); j++) {
                if (A.charAt(i - 1) == B.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        
        return dp[A.length()][B.length()];
    }
}



Lintcode: Longest increasing subsequence (LIS)


Given a sequence of integers, find the longest increasing subsequence (LIS).You code should return the length of the LIS.Example
For [5, 4, 1, 2, 3], the LIS is [1, 2, 3], return 3For [4, 2, 4, 5, 3, 7], the LIS is [4, 4, 5, 7], return 4

Understand the problem:
The longest Increasing Subsequence (LIS) problem is to find the length of the longest subsequence of a given sequence such that all elements of the subsequence are sorted in increasing order. For example, length of LIS for { 10, 22, 9, 33, 21, 50, 41, 60, 80 } is 6 and LIS is {10, 22, 33, 50, 60, 80}.

The problem is a classical computer science problem, LIS. Note that the problem asks to find out the subsequence, not substring. 

A DP Solution:
This is a sequence DP problem, so we define 
  • dp[N], whereas dp[i] denotes the length of the LIS including the array element arr[i]. 
  • Initial state: dp[i] = 1
  • Transit function: for each j, where 0 <= j < i, if (A[i] >= A[j]), dp[i] = Math.max(dp[i], dp[j] + 1);
  • Final state: result = 1, Math.max(result, dp[i]);

Code (Java):
public class Solution {
    /**
     * @param nums: The integer array
     * @return: The length of LIS (longest increasing subsequence)
     */
    public int longestIncreasingSubsequence(int[] nums) {
        // write your code here
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        if (nums.length == 1) {
            return 1;
        }
        
        int[] dp = new int[nums.length];
        for (int i = 0; i < nums.length; i++) {
            dp[i] = 1;
        }
        
        for (int i = 0; i < nums.length; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] >= nums[j]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }
        }
        
        int result = 1;
        for (int i = 0; i < nums.length; i++) {
            result = Math.max(dp[i], result);
        }
        
        return result;
    }
}

A wrong Solution:
Here is a wrong solution using the greedy idea. The basic idea is to use two loops, the outer loop i, starts from 0, and the inner loop starts from i + 1. For each inner loop, we scan through the array and compare the current value with the last one. The code is as follow:

Code (Java):
public class Solution {
    /**
     * @param nums: The integer array
     * @return: The length of LIS (longest increasing subsequence)
     */
    public int longestIncreasingSubsequence(int[] nums) {
        // write your code here
        if (nums == null || nums.length == 0) {
            return 0;
        }
        
        if (nums.length == 1) {
            return 1;
        }
        
        int maxLen = 1;
        for (int i = 0; i < nums.length; i++) {
            int prev = nums[i];
            int len = 1;
            for (int j = i + 1; j < nums.length; j++) {
                if (nums[j] >= prev) {
                    len++;
                    prev = nums[j];
                }
            }
            maxLen = Math.max(maxLen, len);
        }
        
        return maxLen;
    }
}

The code cannot pass the test case :
[10,1,11,2,12,3,11]
where the correct result is 4 (1, 2, 3, 11), but the solution above will generate 3, (1, 11, 12). That is because when j is at 11, it will ignore 2 and generate the incorrect results.

Thursday, September 25, 2014

Leetcode: Longest Valid Parentheses

Given a string containing just the characters '(' and ')', find the length of the longest valid (well-formed) parentheses substring.
For "(()", the longest valid parentheses substring is "()", which has length = 2.
Another example is ")()())", where the longest valid parentheses substring is "()()", which has length = 4.
Understand the problem:
The problem asks for finding the length of the longest valid parentheses substring. Note that it is substring not subsequence. 

Solution 1: Using DP
For those kinds of "longest substring" problems, it is usually to use DP solution. This problem is kind of special using the DP solution. 
1. Define dp[n], whereas dp[i] means the length of the longest valid parentheses substrings STARTING FROM i to str.length() - 1. 
2. Transit function. 
  -- If the str[i] = ')', dp[i] = 0, because there will no well-formed parentheses starting from ')'. 
  -- If the str[i] = '(', we check dp[i + 1], the longest valid parentheses starting from i + 1, and jump to the index j = i + dp[i + 1] + 1. e.g.
( ( ) ( ) )
i          j
So if j is within the length of the string and str[j] == ')', dp[i] = dp[i + 1] + 2. In addition, dp[i] += dp[j + 1], because what if after j the parentheses are still valid. 

3. Initial state: dp[n - 1] = 0
4. Final state: It is quite special here. We cannot check dp[0] because dp[i] stands for the length of longest valid parentheses starting from i. So the longest substring may not starts from str[0]. As a result, we must check if dp[i] is the largest. So the final state is max(dp[i]).

Code (Java):
public class Solution {
    public int longestValidParentheses(String s) {
        if (s == null || s.length() < 2) {
            return 0;
        }
        
        int[] dp = new int[s.length()];
        int maxLen = 0;
        
        for (int i = s.length() - 2; i >= 0; i--) {
            if (s.charAt(i) == '(') {
                int j = i + dp[i + 1] + 1;
                if (j < s.length() && s.charAt(j) == ')') {
                    dp[i] = dp[i + 1] + 2;
                    if (j + 1 < s.length()) {
                        dp[i] += dp[j + 1];
                    }
                }
            }
            
            maxLen = Math.max(maxLen, dp[i]);
        }
        
        return maxLen;
    }
}


Solution 2: Using a stack
public class Solution {
    public int longestValidParentheses(String s) {
        if (s == null || s.length() < 2) {
            return 0;
        }
        
        Stack<Integer> stack = new Stack<Integer>();
        int max = 0;
        int start = 0;
        
        for (int i = 0; i < s.length(); i++) {
            if (s.charAt(i) == '(') {
                stack.push(i);
            } else {
                if (stack.isEmpty()) {
                    start = i + 1;
                } else {
                    stack.pop();
                    if (stack.isEmpty()) {
                        max = Math.max(max, i - start + 1);
                    } else {
                        max = Math.max(max, i - stack.peek());
                    }
                }
            }
        }
        
        return max;
    }
}

Wednesday, September 24, 2014

Leetcode: Candy

There are N children standing in a line. Each child is assigned a rating value.
You are giving candies to these children subjected to the following requirements:
  • Each child must have at least one candy.
  • Children with a higher rating get more candies than their neighbors.
What is the minimum candies you must give?
Understand the problem:
This is a assigning candy problem. There are basically two requirements. First of all, each child must have at least one candy. Secondly, children with a higher rating get more candies than their lower rating neighbor. We can take several examples to show this problem.
For 1   2   3   3   3
      1   2   3    1   1 , so sum = 8

For 1   2   3    2   3
      1   2   3    1    2   so sum = 9

Note that we cannot sort the array, since we must maintain the neighbor relationships between each child. So we can naturally think of using DP to solve this problem.

A DP Solution:

  1. Define a DP array, dp[N], where as dp[i] means number of candies for child i. 
  2. Transit function:  rank[i] > rank[i - 1], dp[i] = dp[i - 1] + 1.  If rank[i] == rank[i - 1], dp[i] = 1. If rank[i] < rank[i -1], it is hard to make a decision since if dp[i - 1] = 1, we cannot let child[i] have 0 candy. So we must go back to plus 1 for all its previous visited children until meet the requirements again.
So we can see that it is actually very complicated using this way. At worst case where the array in sorted in descending order, we need to update all its previous visited children. So the time complexity is O(n^2) in the worst case. 

A better solution:
public class Solution {
    public int candy(int[] ratings) {
        if (ratings == null || ratings.length == 0) {
            return 0;
        }
        
        int[] candy = new int[ratings.length];
        Arrays.fill(candy, 1);
        
        for (int i = 1; i < ratings.length; i++) {
            if (ratings[i] > ratings[i - 1]) {
                candy[i] = candy[i - 1] + 1;
            }
        }
        
        for (int i = ratings.length - 2; i >= 0; i--) {
            if (ratings[i] > ratings[i + 1]) {
                candy[i] = Math.max(candy[i], candy[i + 1] + 1);
            }
        }
        
        int sum = 0;
        for (int i = 0; i < ratings.length; i++) {
            sum += candy[i];
        }
        
        return sum;
    }
}














Tuesday, September 23, 2014

Leetcode: Distinct Subsequences

Given a string S and a string T, count the number of distinct subsequences of T in S.
A subsequence of a string is a new string which is formed from the original string by deleting some (can be none) of the characters without disturbing the relative positions of the remaining characters. (ie, "ACE" is a subsequence of "ABCDE" while "AEC" is not).
Here is an example:
S = "rabbbit"T = "rabbit"
Return 3.
Understand the problem:
The problem gives two strings, S and T, count the number of distinct subsequences of T in S. The problem is a bit of ambiguous. It actually asks that how many distinct subsequences of S which is equal to T. 

Be aware of subsequence and substring. A subsequence of a string is a subset of the string but couldn't disturb the relative positions of the original characters. The main difference between a substring and subsequence is substring must include continuous characters of the original string, whereas subsequence does not need to be, just maintain the relative order of the selected characters. 

DP Solution:
This is a classic DP problem, so we can think of solving this problem using the DP approach.
  1. Define a DP matrix, dp[S.length() + 1][T.length() + 1], whereas dp[i][j] means the number of distinct subsequences from string S[0, i] to string T[0, j].
  2. Initial state: dp[0][0] = 1, dp[0][j] = 0, dp[i][0] = 1
  3. Transit function: For S.charAt(i) == T.charAt(j), dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]. For different, dp[i][j] = dp[i - 1][j]
  4. Final state: dp[S.length()][T.length()]


    #    r   a   b   b   i   t
#   1    0   0   0   0   0   0
r   1    1   0   0   0   0   0
a   1    1   1   0   0   0   0
b   1    1   1   1   0   0   0
b   1    1   1   2   1   0   0
b   1    1   1   3   3   0   0
i   1    1   1   3   3   3   0
t   1    1   1   3   3   3   3 

Code (Java):
public class Solution {
    public int numDistinct(String S, String T) {
        if (S == null || S.length() == 0 || T == null) {
            return 0;
        }
        
        int[][] dp = new int[S.length() + 1][T.length() + 1];
        dp[0][0] = 1;
        
        for (int i = 1; i <= S.length(); i++) {
            dp[i][0] = 1;
        }
        
        for (int i = 1; i <= S.length(); i++) {
            for (int j = 1; j <= T.length(); j++) {
                if (S.charAt(i - 1) == T.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
                } else {
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        
        return dp[S.length()][T.length()];
        
    }
}

Summary:
For DP related problems, it is crucial to figure out how to define the dp matrix and the transit function.

Update on 4/10/19:
public class Solution {
    /**
     * @param S: A string
     * @param T: A string
     * @return: Count the number of distinct subsequences
     */
    public int numDistinct(String S, String T) {
        if (T == null || T.length() == 0) {
            return 1;
        }
        
        int[] dp = new int[T.length() + 1];
        dp[0] = 1;
        
        for (int i = 1; i <= S.length(); i++) {
            dp[0] = 1;
            for (int j = T.length(); j >= 1; j--) {
                if (S.charAt(i - 1) == T.charAt(j - 1)) {
                    dp[j] = dp[j - 1] + dp[j];
                } 
            }
        }
        
        return dp[T.length()];
    }
}