Showing posts with label DP. Show all posts
Showing posts with label DP. Show all posts

Monday, August 7, 2017

[Leetcode] Maximal Square, Solution

Given a 2D binary matrix filled with 0's and 1's, find the largest square containing only 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.


[Thoughts]
这是个DP问题,定义

DP[i, j] 是the length of max square,这个square的最右下角是 (i,j),那么

如果matrix[i][j] == 0, DP[i, j]也是0,因为square 不存在

如果matrix[i][j] == 1, 那么DP[i, j]就有如下三种可能



1)从DP[i-1, j]表述的square上加一行
2)从DP[i, j-1]表述的square上加一列
3)从DP[i-1, j-1]表述的square上加一行和一列

从三种可能中选出最小的那一个就是maximal square。

[Code]
1:    int maximalSquare(vector<vector<char>>& matrix) {  
2:      if(matrix.size() == 0) return 0;  
3:        
4:      int row = matrix.size();  
5:      int col = matrix[0].size();  
6:      vector<vector<int>> dp(row+1, vector<int>(col+1, 0));  
7:        
8:      int maxLen = 0;  
9:      for(int i =1; i<=row; i++) {  
10:        for(int j =1; j<= col; j++) {  
11:          if(matrix[i-1][j-1] == '1') {  
12:            dp[i][j] = min(min(dp[i-1][j-1], dp[i-1][j]), dp[i][j-1])+1 ;  
13:            maxLen = max(maxLen, dp[i][j]);  
14:          }  
15:        }  
16:      }  
17:      return maxLen*maxLen;  
18:    }  


[Leetcode] Perfect Squares, Solution

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.

[Thoughts]
一个一维的DP,比较简单。具体看code


[Code]
1:    int numSquares(int n) {  
2:        
3:      vector<int> dp(n+1, 0);  
4:      for(int i =1; i<= n; i++) {  
5:          
6:        int min_v = INT_MAX;  
7:        for(int j = 1; j*j <= i; j++) {  
8:          min_v = min(min_v, dp[i - j*j] +1);  
9:        }  
10:        dp[i] =min_v;  
11:      }  
12:        
13:      return dp[n];  
14:    }  

[Leetcode] Burst Balloons, Solution

Given n balloons, indexed from 0 to n-1. Each balloon is painted with a number on it represented by array nums. You are asked to burst all the balloons. If the you burst balloon i you will get nums[left] * nums[i] * nums[right] coins. Here left and right are adjacent indices of i. After the burst, the left and right then becomes adjacent.
Find the maximum coins you can collect by bursting the balloons wisely.
Note:
(1) You may imagine nums[-1] = nums[n] = 1. They are not real therefore you can not burst them.
(2) 0 ≤ n ≤ 500, 0 ≤ nums[i] ≤ 100
Example:
Given [3, 1, 5, 8]
Return 167
    nums = [3,1,5,8] --> [3,5,8] -->   [3,8]   -->  [8]  --> []
   coins =  3*1*5      +  3*5*8    +  1*3*8      + 1*8*1   = 167

[Thoughts]
DP题,很有意思。

假设K是range(i,j)中最后一个被戳破的气球,那么我们可以得到

DP[i][j] = max( DP[i][k-1] + nums[i-1]*nums[k]*nums[j+1] + DP[k+1][j])      i<k<j

在计算的过程中从底向上,len是1到n来计算。


[Code]
1:    int maxCoins(vector<int>& nums) {  
2:        
3:      int n = nums.size();  
4:      // add boundary to simplify the corner case  
5:      nums.insert(nums.begin(), 1);  
6:      nums.push_back(1);  
7:        
8:      vector<vector<int>> dp(nums.size(), vector<int>(nums.size(), 0));  
9:        
10:      for(int len = 1; len<=n; len++) {  
11:        for(int left = 1; left<=n-len +1; left++) {  
12:          int right = left + len -1;  
13:          for(int k =left; k<=right; ++k) {  
14:            // K is the Balloons destroyed in the last  
15:            dp[left][right] = max(  
16:              dp[left][right],   
17:              nums[left-1]*nums[k]*nums[right+1] + dp[left][k-1] + dp[k+1][right],  
18:            );  
19:          }  
20:        }  
21:      }  
22:      return dp[1][n];  
23:    }  


Monday, July 24, 2017

[Leetcode] House Robber II, Solution

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.

[Thoughts]
是House Robber的扩展题(http://fisherlei.blogspot.com/2017/07/leetcode-house-robber-solution.html ),唯一的区别就是house 0 和house n-1相邻了。根据题目要求,不能抢劫相邻的房子,所以这个环把它拆开就两种可能:

  1. 抢劫house 0,那么就不能抢劫house n-1,所以抢劫的范围就是[0, n-2]
  2. 不抢劫house 0,那么就得从house 1开始抢,抢劫的范围就是[1, n-1]
对于#1和#2两种情况,都可以复用House Robber的代码, 最后比较一下这两种可能中,那个收入多即可。


[Code]

1:    int rob(vector<int>& nums) {  
2:      int len = nums.size();  
3:        
4:      if(len == 0) return 0;      
5:      if(len == 1) return nums[0];  
6:        
7:      return max(robList(nums, 0, len -2), robList(nums, 1, len-1));  
8:    }  
9:      
10:    int robList(vector<int>& nums, int start, int end) {  
11:      int rob=0, no_rob=0;  
12:      for(int i = start; i<= end; i++) {  
13:        int new_rob = no_rob + nums[i];  
14:        no_rob = max(rob, no_rob);  
15:        rob = new_rob;  
16:      }  
17:        
18:      return max(rob, no_rob);  
19:    }  

Sunday, July 23, 2017

[Leetcode] House Robber, Solution

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.

[Thoughts]
一个dp问题。对于任意一个房子,只有两种状态,rob 或 no_rob.

如果定义 rob[i] 为抢劫house i可获得的最大收益,而no_rob[i] 为不抢劫house i可获得的最大收益,递推关系式可表示为

rob[i] = no_rob[i-1] + house[i];
no_rob[i] = max( rob[i-1], no_rob[i-1]);

如果以 house数组[2,1,1,2]为例,

                            2             1              1               2
            rob           2             1              3               4
           no_rob      0              2             2               3

那么最后的最大收益就是在rob 和no_rob中找个最大的,在此例中就是4


[Code]
实现的时候并不需要真的定义两个数组,用两个临时变量就可以了。
1:    int rob(vector<int>& nums) {  
2:      int len = nums.size();  
3:        
4:      if(len == 0) return 0;  
5:        
6:      if(len == 1) return nums[0];  
7:          
8:      int rob=0, no_rob=0;  
9:      for(int i =0; i< len; i++) {  
10:        int new_rob = no_rob + nums[i];  
11:        no_rob = max(rob, no_rob);  
12:        rob = new_rob;  
13:      }  
14:        
15:      return max(rob, no_rob);  
16:    }  









Saturday, July 22, 2017

[Leetcode] Combination Sum IV, Solution

Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to a positive integer target.
Example:
nums = [1, 2, 3]
target = 4

The possible combination ways are:
(1, 1, 1, 1)
(1, 1, 2)
(1, 2, 1)
(1, 3)
(2, 1, 1)
(2, 2)
(3, 1)

Note that different sequences are counted as different combinations.

Therefore the output is 7.
Follow up:
What if negative numbers are allowed in the given array?
How does it change the problem?
What limitation we need to add to the question to allow negative numbers?

[Thoughts]
这是一个DP问题。对于任意个一个数值n

DP[n] = ∑ DP[target - nums[i]]       0<= i< n



[Code]
1:    int combinationSum4(vector<int>& nums, int target) {  
2:      vector<int> count(target +1, 0);  
3:        
4:      count[0] =1;  
5:      for(int i =1; i<=target; i++) {  
6:        for(int j =0; j< nums.size(); j++) {  
7:          if(i - nums[j] >=0) {  
8:            count[i] += count[i-nums[j]];  
9:          }  
10:        }  
11:      }  
12:        
13:      return count[target];  
14:    }  



Sunday, October 25, 2015

[Leetcode] Product of Array Except Self, Solution

Given an array of n integers where n > 1, nums, return an array output such that output[i] is equal to the product of all the elements of nums except nums[i].
Solve it without division and in O(n).
For example, given [1,2,3,4], return [24,12,8,6].
Follow up:
Could you solve it with constant space complexity? (Note: The output array does not count as extra space for the purpose of space complexity analysis.)
[Thoughts]
一般这种题都可以分解成若干子问题来解决。As defined, 
output[i] is equal to the product of all the elements of nums except nums[i].
简单的说
    output[i] =  { i 前面的数的乘积}  X  { i 后面的数的乘积}
问题就解决了,首先从前往后扫描数组一遍,对每一个i,得到{i 前面的数的乘积}(可以称做output_before),然后在从后往前扫描数组一遍,获得 { i 后面的数的乘积}(可以称做output_after)。 将两数相乘即为所求。
举个例子(如下图),nums = {1,2,3,4}, 第一遍,从前往后扫描一遍,得到的output_before = {1, 1, 2, 6}. 从后往前扫描一遍,得到的output_after = {24, 12, 4, 1}.
那么  output [i] = output_before[i] * output_after[i],   output = {24, 12, 8, 6}

[Code]
1:  class Solution {  
2:  public:  
3:    vector<int> productExceptSelf(vector<int>& nums) {  
4:      vector<int> products;  
5:      if(nums.size() == 0) return products;  
6:      int product = 1;  
7:      products.push_back(1);  
8:      for(int i =1; i< nums.size(); i++) {  
9:        product *= nums[i-1];  
10:        products.push_back(product);  
11:      }  
12:      product = 1;  
13:      for(int i =nums.size()-2; i>=0; i--) {  
14:        product = product * nums[i+1];  
15:        products[i] = products[i] * product;   
16:      }  
17:      return products;  
18:    }  
19:  };  

github: https://github.com/codingtmd/leetcode/blob/master/src/Product%20of%20Array%20Except%20Self.cpp
另一种解法,可以分成三种情况:
  1. 数组中有一个以上的0出现, 比如 [1,2, 0, 0, 3, 4], 最后的结果肯定都是0: [0,0,0,0,0,0]
  2. 数组中有一个0出现,比如[1,2,0,3,4],按照题目的定义,最后的输出结果是[0,0,24,0,0]. 除了0的那一位是有值,其他位都是0
  3. 数组中没有0, 假设数组位[a0, a1, a2, ......], 其中所有数值的乘积为M, 那个数组的输出就是[M/a0, M/a1, M/a2.....].

[Code]
1:    vector<int> productExceptSelf(vector<int>& nums) {  
2:      int64_t product = 1;  
3:        
4:      int zeros = 0;  
5:      for(int i =0; i< nums.size(); i++) {  
6:        if(nums[i] == 0){  
7:          zeros++;  
8:          continue;  
9:        }   
10:        product *= nums[i];  
11:      }  
12:        
13:      vector<int> result;  
14:      for(int i =0; i< nums.size(); i++) {  
15:        if(zeros > 1) {  
16:          result.push_back(0);  
17:          continue;  
18:        } else if( zeros == 1){  
19:          if(nums[i] == 0) result.push_back(product);  
20:          else result.push_back(0);  
21:          continue;  
22:        }  
23:          
24:        result.push_back(product/nums[i]);  
25:      }  
26:        
27:      return result;  
28:    }  

Monday, November 18, 2013

[LeetCode] Word Break, Solution

Given a string s and a dictionary of words dict, determine if s can be segmented into a space-separated sequence of one or more dictionary words.

For example, given
s = "leetcode",
dict = ["leet", "code"].

Return true because "leetcode" can be segmented as "leet code".

[Thoughts]

一个DP问题。定义possible[i] 为S字符串上[0,i]的子串是否可以被segmented by dictionary.

那么

possible[i] = true      if  S[0,i]在dictionary里面

                = true      if   possible[k] == true 并且 S[k+1,j]在dictionary里面, 0<k<i

               = false      if    no such k exist.

 

[Code]

实现时前面加一个dummy节点,这样可以把三种情况统一到一个表达式里面。

1 bool wordBreak(string s, unordered_set<string> &dict) {
2 string s2 = '#' + s;
3 int len = s2.size();
4 vector<bool> possible(len, 0);
5
6 possible[0] = true;
7 for(int i =1; i< len; ++i)
8 {
9 for(int k=0; k<i; ++k)
10 {
11 possible[i] = possible[k] &&
12 dict.find(s2.substr(k+1, i-k)) != dict.end();
13 if(possible[i]) break;
14 }
15 }
16
17 return possible[len-1];
18 }

Wednesday, November 13, 2013

[LeetCode] Candy, Solution

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?
[Thoughts]
蛮好玩的题。感觉用dp简单点。定义Candy[i]为第i个孩子需要给的最少的糖数,
那么
Candy[i] =            Candy[i-1]+1  if ratings[i] > ratings[i-1] 递增序列,后面小孩需要的糖果是前一个小孩的糖果数+1
                           1                   if ratings[i] == ratings[i-1] 直线,按照题意,如果两个小孩rating一样多,后面的小孩可以只拿一个糖
                           Candy[i-1] –1 if ratings[i] < ratings[i-1] 递减序列。这个递推式显然是有缺陷,因为如果递减序列比较长的话,Candy[i]就可能出现负值了,负值显然是没有意义的。比如下图为例:
蓝线是rating变化曲线,数字是Candy[i]的值。基于上面递推式的解(第一行)明显是不合理的。而第二行经过调整的(红色数字),才是最优解。简单的说,就是当遇到一个波谷的时候,调整一下左边的下降序列就好了,但是要注意区分条件,上一个波峰只在有些条件下才需要更改(例一和例二的区别)。
image


[Code]
1:         int candy(vector<int> &ratings) {  
2:            vector<int> candy(ratings.size());  
3:            candy[0] = 1;  
4:            int i =1;  
5:            for (; i < ratings.size(); ++i)  
6:            {  
7:                 if (ratings[i] > ratings[i-1]) //递增  
8:                 {  
9:                      candy[i] = candy[i - 1] + 1;  
10:                 }  
11:                 if (ratings[i] == ratings[i-1]) //平行  
12:                 {  
13:                      candy[i] = 1;  
14:                 }  
15:                 if (ratings[i] < ratings[i - 1]) //递减  
16:                 {  
17:                      candy[i] = candy[i - 1] - 1;  
18:                 }  
19:                 if (i<ratings.size()-1 && ratings[i] < ratings[i-1] && ratings[i] <=ratings[i+1])  
20:                      ReAdjustCandy(ratings, candy, i);  
21:            }  
22:            if (ratings[i-1] < ratings[i-2])  
23:                 ReAdjustCandy(ratings, candy, ratings.size() - 1);  
24:            int total = 0;  
25:            std::for_each(candy.begin(), candy.end(), [&](int n){  
26:                 total += n;  
27:            });  
28:            return total;  
29:       }  
30:       void ReAdjustCandy(vector<int>& ratings, vector<int>& candy, int startIndex)  
31:       {  
32:            int k = startIndex;  
33:            int diff = 1 - candy[k];  
34:            while (k > 0 && ratings[k - 1] > ratings[k])  
35:            {  
36:                 candy[k] = candy[k] + diff;  
37:                 k--;  
38:            }  
39:            if (diff > 0) candy[k] += diff;  
40:       }  



Wednesday, March 20, 2013

[LeetCode] Unique Binary Search Trees, Solution


Given n, how many structurally unique BST's (binary search trees) that store values 1...n?
For example,
Given n = 3, there are a total of 5 unique BST's.
   1         3     3      2      1
    \       /     /      / \      \
     3     2     1      1   3      2
    /     /       \                 \
   2     1         2                 3
» Solve this problem

[Thoughts]
这题想了好久才想清楚。其实如果把上例的顺序改一下,就可以看出规律了。
 1                1                      2                       3             3
    \                 \                 /      \                  /              /
      3               2              1       3               2             1
    /                   \                                       /                  \
 2                       3                                   1                    2

比如,以1为根的树有几个,完全取决于有二个元素的子树有几种。同理,2为根的子树取决于一个元素的子树有几个。以3为根的情况,则与1相同。

定义Count[i] 为以[0,i]能产生的Unique Binary Tree的数目,

如果数组为空,毫无疑问,只有一种BST,即空树,
Count[0] =1

如果数组仅有一个元素{1},只有一种BST,单个节点
Count[1] = 1

如果数组有两个元素{1,2}, 那么有如下两种可能
1                       2
  \                    /
    2                1
Count[2] = Count[0] * Count[1]   (1为根的情况)
                  + Count[1] * Count[0]  (2为根的情况。

再看一遍三个元素的数组,可以发现BST的取值方式如下:
Count[3] = Count[0]*Count[2]  (1为根的情况)
               + Count[1]*Count[1]  (2为根的情况)
               + Count[2]*Count[0]  (3为根的情况)

所以,由此观察,可以得出Count的递推公式为
Count[i] = ∑ Count[0...k] * [ k+1....i]     0<=k<i-1
问题至此划归为一维动态规划。

[Code]
1:       int numTrees(int n) {  
2:            vector<int> count(n+1, 0);  
3:            count[0] =1;  
4:            count[1] =1;  
5:            for(int i =2; i<=n; i++)  
6:            {  
7:                 for(int j =0; j<i; j++)  
8:                 {  
9:                      count[i] += count[j]*count[i-j-1];   
10:                 }  
11:            }  
12:            return count[n];  
13:       }  


[Note]
这是很有意思的一个题。刚拿到这题的时候,完全不知道从那下手,因为对于BST是否Unique,很难判断。最后引入了一个条件以后,立即就清晰了,即
当数组为 1,2,3,4,.. i,.. n时,基于以下原则的BST建树具有唯一性:
以i为根节点的树,其左子树由[0, i-1]构成, 其右子树由[i+1, n]构成。



Monday, March 4, 2013

[LeetCode] Palindrome Partitioning II, Solution

Given a string s, partition s such that every substring of the partition is a palindrome.
Return the minimum cuts needed for a palindrome partitioning of s.
For example, given s = "aab",
Return 1 since the palindrome partitioning ["aa","b"] could be produced using 1 cut.
» Solve this problem

[Thoughts]
凡是求最优解的,一般都是走DP的路线。这一题也不例外。首先求dp函数,

定义函数
D[i,n] = 区间[i,n]之间最小的cut数,n为字符串长度

 a   b   a   b   b   b   a   b   b   a   b   a
                     i                                  n
如果现在求[i,n]之间的最优解?应该是多少?简单看一看,至少有下面一个解


 a   b   a   b   b   b   a   b   b   a   b   a
                     i                   j   j+1     n

此时  D[i,n] = min(D[i, j] + D[j+1,n])  i<=j <n。这是个二维的函数,实际写代码时维护比较麻烦。所以要转换成一维DP。如果每次,从i往右扫描,每找到一个回文就算一次DP的话,就可以转换为
D[i] = 区间[i,n]之间最小的cut数,n为字符串长度, 则,

D[i] = min(1+D[j+1] )    i<=j <n

有个转移函数之后,一个问题出现了,就是如何判断[i,j]是否是回文?每次都从i到j比较一遍?太浪费了,这里也是一个DP问题。
定义函数
P[i][j] = true if [i,j]为回文

那么
P[i][j] = str[i] == str[j] && P[i+1][j-1];

基于以上分析,实现如下:
1:       int minCut(string s) {  
2:            int len = s.size();  
3:            int D[len+1];  
4:            bool P[len][len];  
5:            //the worst case is cutting by each char  
6:            for(int i = 0; i <= len; i++)   
7:            D[i] = len-i;  
8:            for(int i = 0; i < len; i++)  
9:            for(int j = 0; j < len; j++)  
10:            P[i][j] = false;  
11:            for(int i = len-1; i >= 0; i--){  
12:                 for(int j = i; j < len; j++){  
13:                      if(s[i] == s[j] && (j-i<2 || P[i+1][j-1])){  
14:                           P[i][j] = true;  
15:                           D[i] = min(D[i],D[j+1]+1);  
16:                      }  
17:                 }  
18:            }  
19:            return D[0]-1;  
20:       }  


或者可以考虑使用回溯+剪枝,比如:

1:    int minCut(string s) {  
2:      int min = INT_MAX;  
3:      DFS(s, 0, 0, min);  
4:      return min;  
5:    }  
6:    void DFS(string &s, int start, int depth, int& min)  
7:    {     
8:      if(start == s.size())  
9:      {  
10:        if(min> depth-1)  
11:          min = depth-1;  
12:        return;  
13:      }  
14:      for(int i = s.size()-1; i>=start; i--)  //find the biggest palindrome first
15:      {  
16:        if(isPalindrome(s, start, i))  
17:        {        
18:          DFS(s, i+1, depth+1, min);  
19:        }  
20:        if(min!=INT_MAX)  //if get result, then stop search.
21:          break;  
22:      }  
23:    }  
24:    bool isPalindrome(string &s, int start, int end)  
25:    {  
26:      while(start< end)  
27:      {  
28:        if(s[start] != s[end])  
29:          return false;  
30:        start++; end--;  
31:      }  
32:      return true;  
33:    }  

Saturday, February 23, 2013

[LeetCode] Longest Consecutive Sequence, Solution


Given an unsorted array of integers, find the length of the longest consecutive elements sequence.
For example,
Given [100, 4, 200, 1, 3, 2],
The longest consecutive elements sequence is [1, 2, 3, 4]. Return its length: 4.
Your algorithm should run in O(n) complexity.
» Solve this problem

[Thoughts]
Since it requires O(n) solution, normal sort won't be work here. Hash probably is the best choice.
3 Steps:
1. create the hashmap to hold <num, index>
2. scan the num vector from left to right, for each num
               i, check whether num -1 is in the map  (loop)
              ii, check whether num+1 is in the map  (loop)
3. track the sequence length during scanning.

[Code]
1:       int longestConsecutive(vector<int> &num) {  
2:            unordered_map<int, int> hashmap;            
3:            for(int i =0; i< num.size(); i++)  
4:            {  
5:                 hashmap[num[i]] = i;  
6:            }  
7:            vector<int> visited(num.size(), 0);  
8:            int maxV = INT_MIN;  
9:            for(int i =0; i< num.size(); i++)  
10:            {  
11:                 if(visited[i]==1) continue;  
12:                 visited[i]=1;  
13:                 int len = 1;  
14:                 int index = num[i]-1;  
15:                 while(hashmap.find(index) != hashmap.end())  
16:                 {  
17:                      visited[hashmap[index]] =1;  
18:                      index--;  
19:                      len++;  
20:                 }  
21:                 index = num[i]+1;  
22:                 while(hashmap.find(index) != hashmap.end())  
23:                 {  
24:                      visited[hashmap[index]] =1;  
25:                      index++;  
26:                      len++;  
27:                 }  
28:                 if(len > maxV)  
29:                      maxV = len;  
30:            }  
31:            return maxV;  
32:       }  



Update 08/23/2014
Interesting discussion in the comments:) I haven't visited my blog for quite long time.

For each num, define D[num] as the longest consecutive sequence from k to num,  0<k<num

So D[num] = D[num-1] +1   if num-1 in the map
                  =0                      if num-1  not in the map

But unfortunately, the unordered_map doesn't keep any order of sequence. It's hard to do the DP via a loop.

Here can use Memorization to optimize the code. Since for each fresh node, it only visits once. It is O(n) code.

And in the code , the second 'for' loop and the third 'for' loop could be merged together, but here keep them separated for readability.

1:       int longestConsecutive(vector<int> &num) {  
2:            unordered_map<int, int> hashmap;  
3:            vector<int> length(num.size(),0);  
4:            for(int i =0; i< num.size(); i++)  
5:            {  
6:                 hashmap[num[i]]=i;  
7:            }  
8:            for(int i =0; i< num.size(); i++)  
9:            {  
10:                 // skip the node, which already calculate the length  
11:                 if(length[i] > 0) continue;                 
12:                 length[i] = consecutiveLength(num[i], hashmap, length);  
13:            }  
14:            int maxV = INT_MIN;  
15:            for(int i =0; i< num.size(); i++)  
16:            {  
17:                 maxV = length[i]>maxV?length[i]:maxV;  
18:            }  
19:            return maxV;  
20:       }  
21:       int consecutiveLength(int num, unordered_map<int, int>& hashmap, vector<int>& length)  
22:       {  
23:            if(hashmap.find(num) == hashmap.end()) return 0;  
24:            int index = hashmap[num];  
25:            // skip the node, which already calculate the length  
26:            if(length[index] > 0) return length[index];  
27:            else  
28:            {  
29:                 // hit each fresh node only once  
30:                 length[index] = consecutiveLength(num - 1, hashmap, length) + 1;  
31:                 return length[index];  
32:            }  
33:       }  




Saturday, January 26, 2013

[LeetCode] Climbing Stairs, Solution


You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
» Solve this problem

[Thoughts]
DP. The transition function should be:
 f(n) = f(n-1) + f(n-2)  n>2;
     or = 1   n=1
    or  = 2   n=2


[Code]
1:    int climbStairs(int n) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int fn_2 =1, fn_1=2;  
5:      if(n==1) return fn_2;  
6:      if(n ==2) return fn_1;  
7:      int fn;  
8:      for(int i =3; i<=n; i++)  
9:      {  
10:        fn = fn_2+fn_1;  
11:        fn_2 = fn_1;  
12:        fn_1= fn;  
13:      }  
14:      return fn;  
15:    }  


Wednesday, January 16, 2013

[LeetCode] Best Time to Buy and Sell Stock III Solution


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 two transactions.
Note:
You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
» Solve this problem

[Thoughts]
One dimensional dynamic planning.
Given an i, split the whole array into two parts:
[0,i] and [i+1, n], it generates two max value based on i, Max(0,i) and Max(i+1,n)
So, we can define the transformation function as:
Maxprofix = max(Max(0,i) + Max(i+1, n))  0<=i<n
Pre-processing Max(0,i) might be easy, but I didn't figure an efficient way to generate Max(i+1,n) in one pass.

[Code]
1:    int maxProfit(vector<int> &prices) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int index =0;  
5:      int max1, max2;  
6:      int max =0;  
7:      for(int i =0; i< prices.size(); i++)  
8:      {  
9:        max1=SearchMax(prices,0,i);  
10:        max2 = SearchMax(prices,i+1, prices.size()-1);  
11:        if(max < max1+max2)  
12:          max = max1+max2;  
13:      }  
14:      return max;  
15:    }  
16:    int SearchMax(vector<int>& prices, int start, int end)  
17:    {  
18:      int max=0;  
19:      int min=INT_MAX;  
20:      for(int i =start; i<= end; i++)  
21:      {  
22:        if(min> prices[i]) min = prices[i];  
23:        int diff = prices[i] -min;  
24:        if(diff> max)  
25:        {  
26:          max = diff;          
27:        }  
28:      }  
29:      return max;  
30:    }  

Update 03/12/2014
Just see the comments. Looks I didn't post the right code.
Line 6~12 and Line 15~21 can be merged into one pass. But keep it for readability.

1:  int maxProfit(vector<int> &prices) {   
2:       if(prices.size() <= 1) return 0;  
3:       vector<int> maxFromLeft(prices.size(), 0);  
4:       vector<int> maxFromRight(prices.size(), 0);  
5:       int minV = INT_MAX, maxP = INT_MIN;  
6:       for(int i =0; i< prices.size(); i++)  
7:       {  
8:            if(minV > prices[i]) minV = prices[i];  
9:            int temp = prices[i] - minV;  
10:            if(temp > maxP) maxP = temp;  
11:            maxFromLeft[i] = maxP;  
12:       }  
13:       int maxV = INT_MIN;  
14:       maxP = INT_MIN;  
15:       for(int i =prices.size()-1; i>=0; i--)  
16:       {  
17:            if(maxV < prices[i]) maxV = prices[i];  
18:            int temp = maxV - prices[i];  
19:            if(temp > maxP) maxP = temp;  
20:            maxFromRight[i] = maxP;  
21:       }  
22:       int maxProfit = INT_MIN;  
23:       for(int i =0; i< prices.size()-1; i++)  
24:       {  
25:            int sum = maxFromLeft[i] + maxFromRight[i+1];  
26:            if(sum > maxProfit) maxProfit = sum;  
27:       }  
28:       if(maxProfit < maxFromRight[0])  
29:            maxProfit = maxFromRight[0];  
30:       return maxProfit;   
31:  }   






Thursday, January 10, 2013

[LeetCode] Unique Paths II 解题报告

Follow up for "Unique Paths":

Now consider if some obstacles are added to the grids. How many unique paths would there be?
An obstacle and empty space is marked as 1 and 0 respectively in the grid.
For example,
There is one obstacle in the middle of a 3x3 grid as illustrated below.
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
The total number of unique paths is 2.
Note: m and n will be at most 100.
» Solve this problem

[解题思路]
和Unique Path一样的转移方程:
Step[i][j] = Step[i-1][j] + Step[i][j-1] if Array[i][j] ==0
or            = 0 if Array[i][j] =1


[Code]
1:       int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) {  
2:            int m = obstacleGrid.size();  
3:            if(m ==0) return 0;  
4:            int n = obstacleGrid[0].size();  
5:            if(obstacleGrid[0][0] ==1) return 0;  
6:            vector<int> maxV(n,0);  
7:            maxV[0] =1;  
8:            for(int i =0; i<m; i++)  
9:            {  
10:                 for(int j =0; j<n; j++)  
11:                 {  
12:                      if(obstacleGrid[i][j] ==1)  
13:                           maxV[j]=0;  
14:                      else if(j >0)  
15:                           maxV[j] = maxV[j-1]+maxV[j];  
16:                 }  
17:            }  
18:            return maxV[n-1];  
19:       }  




[LeetCode] Unique Paths 解题报告


Ranking: **
A robot is located at the top-left corner of a m x n grid (marked 'Start' in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked 'Finish' in the diagram below).
How many possible unique paths are there?
Above is a 3 x 7 grid. How many possible unique paths are there?
Note: m and n will be at most 100.
» Solve this problem

[解题思路]
一维DP。 Step[i][j] = Step[i-1][j] + Step[i][j-1];


[Code]
1:       int uniquePaths(int m, int n) {  
2:            vector<int> maxV(n,0);  
3:            maxV[0]=1;  
4:            for(int i =0; i< m; i++)  
5:            {  
6:                 for(int j =1; j<n; j++)  
7:                 {  
8:                      maxV[j] = maxV[j-1] + maxV[j];  
9:                 }  
10:            }  
11:            return maxV[n-1];  
12:       }  



Wednesday, January 9, 2013

[LeetCode] Triangle 解题报告



Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.
For example, given the following triangle
[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]
The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).
Note:
Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.
» Solve this problem

[解题思路]

一维DP。逐行扫描,每一个位置能取得的最小sum,是该元素上面两个能取得的最小sum中最小的那一个sum加上自己的值。只需要开一个数组重复利用就行了。

实现的时候,有些繁琐的地方,这个题比较好从下往上扫描。如果从上往下,其中minV的初始值问题就很头疼。


[Code]

1:    int minimumTotal(vector<vector<int> > &triangle) {  
2:      int row = triangle.size();  
3:      if(row ==0) return 0;  
4:      vector<int> minV(triangle[row-1].size());  
5:      for(int i =row-1; i>=0; i--)  
6:      {  
7:        int col = triangle[i].size();  
8:        for(int j =0; j<col; j++)  
9:        {  
10:          if(i == row-1)  
11:          {  
12:            minV[j] = triangle[i][j];  
13:            continue;  
14:          }  
15:          minV[j] = min(minV[j], minV[j+1]) + triangle[i][j];  
16:        }  
17:      }  
18:      return minV[0];  
19:    }  


Thursday, December 27, 2012

[LeetCode] Minimum Path Sum 解题报告

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.
Note: You can only move either down or right at any point in time.
» Solve this problem

[解题报告]
二维DP。设数组A[row][col],
Min[i][j] = min(Min[i-1][j], Min[i][j-1]) +A[i][j];
注意初始条件即可。

[Code]
1:    int minPathSum(vector<vector<int> > &grid) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function      
4:      if(grid.size() ==0) return 0;  
5:      int row = grid.size();  
6:      int col = grid[0].size();  
7:      int Min[row][col];  
8:      Min[0][0] =grid[0][0];  
9:      for(int i =1; i < row; i ++)  
10:      {  
11:        Min[i][0] =Min[i-1][0] + grid[i][0];  
12:      }  
13:      for(int i =1; i< col; i++)  
14:      {  
15:        Min[0][i] = Min[0][i-1] + grid[0][i];  
16:      }  
17:      for(int i =1; i< row; i++)  
18:      {  
19:        for(int j =1; j< col; j++)  
20:        {  
21:          Min[i][j] = min(Min[i-1][j], Min[i][j-1]) + grid[i][j];  
22:        }  
23:      }  
24:      return Min[row-1][col-1];  
25:    }  

Update: 3/16/2013. Refactor code
没必要用二维数组,用滚动数组即可。

1:    int minPathSum(vector<vector<int> > &grid) {  
2:      int row = grid.size();  
3:      if(row == 0) return 0;      
4:      int col = grid[0].size();  
5:      if(col == 0) return 0;  
6:      vector<int> steps(col, INT_MAX);  
7:      steps[0] =0;  
8:      for(int i =0; i< row; i++)  
9:      {  
10:          steps[0] = steps[0] + grid[i][0];  
11:          for(int j=1; j<col; j++)  
12:          {  
13:             steps[j]=min(steps[j], steps[j-1]) + grid[i][j];  
14:          }  
15:      }  
16:      return steps[col-1];  
17:    }  
注意,Line 6,初始值是INT_MAX。因为Line 13里面用了min函数。


Tuesday, December 25, 2012

[LeetCode] Maximum Subarray 解题报告


Find the contiguous subarray within an array (containing at least one number) which has the largest sum.
For example, given the array [−2,1,−3,4,−1,2,1,−5,4],
the contiguous subarray [4,−1,2,1] has the largest sum = 6.
More practice:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.
» Solve this problem

[解题思路]
O(n)就是一维DP.
假设A(0, i)区间存在k,使得[k, i]区间是以i结尾区间的最大值, 定义为Max[i], 在这里,当求取Max[i+1]时,
Max[i+1] = Max[i] + A[i+1],  if (Max[i] + A[i+1] >0)
                = 0, if(Max[i]+A[i+1] <0),如果和小于零,A[i+1]必为负数,没必要保留,舍弃掉
然后从左往右扫描,求取Max数字的最大值即为所求。

[Code]
1:    int maxSubArray(int A[], int n) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int sum = 0;  
5:      int max = INT_MIN;  
6:      for(int i =0; i < n ; i ++)  
7:      {  
8:        sum +=A[i];        
9:        if(sum>max)  
10:          max = sum;  
11:        if(sum < 0)  
12:          sum = 0;  
13:      }  
14:      return max;  
15:    }  

但是题目中要求,不要用这个O(n)解法,而是采用Divide & Conquer。这就暗示了,解法必然是二分。分析如下:

假设数组A[left, right]存在最大值区间[i, j](i>=left & j<=right),以mid = (left + right)/2 分界,无非以下三种情况:

subarray A[i,..j] is
(1) Entirely in A[low,mid-1]
(2) Entirely in A[mid+1,high]
(3) Across mid
对于(1) and (2),直接递归求解即可,对于(3),则需要以min为中心,向左及向右扫描求最大值,意味着在A[left, Mid]区间中找出A[i..mid], 而在A[mid+1, right]中找出A[mid+1..j],两者加和即为(3)的解。

代码实现如下:
1:    int maxSubArray(int A[], int n) {  
2:      // Start typing your C/C++ solution below  
3:      // DO NOT write int main() function  
4:      int maxV = INT_MIN;  
5:      return maxArray(A, 0, n-1, maxV);      
6:    }  
7:    int maxArray(int A[], int left, int right, int& maxV)  
8:    {  
9:      if(left>right)  
10:        return INT_MIN;  
11:      int mid = (left+right)/2;  
12:      int lmax = maxArray(A, left, mid -1, maxV);  
13:      int rmax = maxArray(A, mid + 1, right, maxV);  
14:      maxV = max(maxV, lmax);  
15:      maxV = max(maxV, rmax);  
16:      int sum = 0, mlmax = 0;  
17:      for(int i= mid -1; i>=left; i--)  
18:      {  
19:        sum += A[i];  
20:        if(sum > mlmax)  
21:          mlmax = sum;  
22:      }  
23:      sum = 0; int mrmax = 0;  
24:      for(int i = mid +1; i<=right; i++)  
25:      {  
26:        sum += A[i];  
27:        if(sum > mrmax)  
28:          mrmax = sum;  
29:      }  
30:      maxV = max(maxV, mlmax + mrmax + A[mid]);  
31:      return maxV;  
32:    }  

[注意]
考虑到最大和仍然可能是负数,所以对于有些变量的初始化不能为0,要为INT_MIN。