House Robber I && II – dp

House Robber I
public class Solution {
public int rob(int[] nums) {
if (nums.length==0) return 0;

int last1=0;
int last2=nums[0];
for(int i=1;i<nums.length;i++){
int temp=Math.max(last1+nums[i],last2);
last1=last2;
last2=temp;
}

return last2;
}
}
House Robber II
public class Solution {
public int rob(int[] nums) {
if (nums.length==0) return 0;
if (nums.length==1) return nums[0];
int[] dp=new int[nums.length];
//include 1st one, not last one
dp[0]=nums[0];
dp[1]=nums[0];
for(int i=2;i<nums.length-1;i++){
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
int max1=dp[nums.length-2];
//include last one, not include the first one
dp[0]=0;
dp[1]=nums[1];
for(int i=2;i<nums.length;i++){
dp[i]=Math.max(dp[i-1],dp[i-2]+nums[i]);
}
return Math.max(max1,dp[nums.length-1]);
}
}

House Robber I && II – dp

Palindrome — Lintcode

1.Valid Palindrome – 这道题简单,就是两边同时扫描,O(N)

2. Palindrome Partitioning -recursive的做法

3. Palindrome Partitioning II - 用同样recursive做法就超时了。是double dp题目

4. Longest Palindrome -
O(n^2)算法不难-遍历一边,两种情况,1) 某个点i作为center各往左右,2)i 和i+1分别为center往左右
O(n)算法很巧妙http://articles.leetcode.com/2011/11/longest-palindromic-substring-part-ii.html

Palindrome — Lintcode

Maximum/Minimum Subarray – lintcode

1.Maximum/Minimum Subarray - 只需要scan一次求出global最大值/最小值。
Maximum Product Subarray – scan一次,需要两个数组记住最大最小值,tricky:最小值*最小可能是最大。
2.Maximum Subarray II-是上面题目变形。需要scan两次,left/right 各一次。
思考:动态规划中很多时候需要一个local最大值和global最大值。
loop1 是求出包括当前点,也就是local的最大值。
loop2 求出到达当前点的global值,不一定要包括当前。
loop1 and loop2是可以合并写成一个loop的。

  public int maxTwoSubArrays(ArrayList<Integer> nums) {
	        if (nums==null||nums.size()==0){
	            return 0;
	        }
	        int len=nums.size();
	        int[] left=new int[len];
	        int[] right=new int[len];
	        left[0]=nums.get(0);
	        right[len-1]=nums.get(len-1);
	        for(int i=1;i<len;i++){  //loop1
	            left[i]=Math.max(nums.get(i),left[i-1]+nums.get(i));
	        }
	        int curMax=left[0];
	        for(int i=1;i<len;i++){//loop2
	            int temp=Math.max(left[i],curMax);
	            left[i]=temp;
	            curMax=temp;
	        }
	        for(int i=len-2;i>=0;i--){
	            right[i]=Math.max(nums.get(i),right[i+1]+nums.get(i));
	        }
	        curMax=right[len-1];
	         for(int i=len-2;i>=0;i--){
	            int temp=Math.max(curMax,right[i]);
	            curMax=temp;
	            right[i]=curMax;
	        }
	        int max=Integer.MIN_VALUE;
	        for(int i=0;i<len-1;i++){ 
	            max=Math.max(left[i]+right[i+1],max);
	        }
	        return max;
	    }

3.Maximum Subarray Difference 需要scan left/right 的最大和最小值
比较差值 Math.max(Math.abs(lMax[i]-rMin[i+1]),Math.abs(lMin[i]-rMax[i+1])

 public int maxDiffSubArrays(ArrayList<Integer> nums) {
        if (nums.size()==0) return 0;
        int len=nums.size();
        int[] lMax=new int[len];
        int[] lMin=new int[len];
        int[] rMax=new int[len];
        int[] rMin=new int[len];
        int localMin=0;
        int localMax=0;
        int max=Integer.MIN_VALUE;
        int min=Integer.MAX_VALUE;
        for(int i=0;i<len;i++){
            int temp=nums.get(i);
            localMax=Math.max(temp,temp+localMax);
            max=Math.max(max,localMax);
            lMax[i]=max;
            localMin=Math.min(temp,temp+localMin);
            min=Math.min(min,localMin);
            lMin[i]=min;
            
        }
        localMin=0;
        localMax=0;
        max=Integer.MIN_VALUE;
        min=Integer.MAX_VALUE;
        for(int i=len-1;i>=0;i--){
            int temp=nums.get(i);
            localMax=Math.max(temp,temp+localMax);
            max=Math.max(max,localMax);
            rMax[i]=max;
            localMin=Math.min(temp,temp+localMin);
            min=Math.min(min,localMin);
            rMin[i]=min;
        }
        max=Integer.MIN_VALUE;
        for(int i=0;i<len-1;i++){
            int temp=Math.max(Math.abs(lMax[i]-rMin[i+1]),Math.abs(lMin[i]-rMax[i+1]));
            max=Math.max(temp,max);
        }
        return max;
    }

4. Maximum Subarray III
dp二维数组
http://www.cnblogs.com/lishiblog/p/4183917.html

5.Minimum Size Subarray Sum( sliding window 做法)
http://techinpad.blogspot.com/2015/05/leetcode-minimum-size-subarray-sum.html
http://blog.csdn.net/nicaishibiantai/article/details/45814397

Maximum/Minimum Subarray – lintcode

Best Time to Buy and Sell Stock – LintCode

一共4道题

Best Time to Buy and Sell Stock I -求一次最大值,遍历一边,求最大差

Best Time to Buy and Sell Stock II -遍历一边, 把连续单递增数列里的头尾差值相加

Best Time to Buy and Sell Stock III -at most two transanction – O(n)space O(n) time

  • scan from left to right, store max in an array
  • for (int i = 1; i < prices.length; i++) {
                min = Math.min(prices[i], min);
                left[i] = Math.max(left[i - 1], prices[i] - min);
            }
  • scan right to left
    for (int i = prices.length - 2; i >= 0; i--) {
                max = Math.max(prices[i], max);
                right[i] = Math.max(right[i + 1], max - prices[i]);
            }

Best Time to Buy and Sell Stock IV — at most k transactions

  • if k > array.len/2; 就是Best Time to Buy and Sell Stock II
  • 解释http://blog.csdn.net/linhuanmars/article/details/23236995
  • https://gist.github.com/ElninoFong/d08051d98e634991cd93
  • 使用“局部最优和全局最优解法”。
    我们维护两种量,一个是当前到达第i天可以最多进行j次交易,最好的利润是多少(global[i][j]),
    另一个是当前到达第i天,最多可进行j次交易,并且最后一次交易在当天卖出的最好的利润是多少(local[i][j])。
    下面我们来看递推式,全局的比较简单,
    global[i][j]=max(local[i][j],global[i-1][j]),
    也就是去当前局部最好的,和过往全局最好的中大的那个(因为最后一次交易如果包含当前天一定在局部最好的里面,
    否则一定在过往全局最优的里面)。
    全局(到达第i天进行j次交易的最大收益) = max{局部(在第i天交易后,恰好满足j次交易),全局(到达第j-1天时已经满足j次交易)}
  • 对于局部变量的维护,递推式是
    local[i][j]=max(global[i-1][j-1]+max(diff,0),local[i-1][j]+diff),
    也就是看两个量,第一个是全局到i-1天进行j-1次交易,然后加上今天的交易,
    如果今天是赚钱的话(也就是前面只要j-1次交易,最后一次交易取当前天),
    第二个量则是取local第i-1天j次交易,然后加上今天的差值
    (这里因为local[i-1][j]比如包含第i-1天卖出的交易,所以现在变成第i天卖出,
    并不会增加交易次数,而且这里无论diff是不是大于0都一定要加上,
    因为否则就不满足local[i][j]必须在最后一天卖出的条件了)。
    局部(在第i天交易后,总共交易了j次) = max{情况2,情况1}
    情况1:在第i-1天时,恰好已经交易了j次(local[i-1][j]),那么如果i-1天到i天再交易一次:
    即在第i-1天买入,第i天卖出(diff),则这不并不会增加交易次数!
    【例如我在第一天买入,第二天卖出;然后第二天又买入,第三天再卖出的行为 和 第一天买入,
    第三天卖出 的效果是一样的,其实只进行了一次交易!因为有连续性】
    情况2:第i-1天后,共交易了j-1次(global[i-1][j-1]),因此为了满足“第i天过后共进行了j次交易,
    且第i天必须进行交易”的条件:我们可以选择1:在第i-1天买入,然后再第i天卖出(diff),
    或者选择在第i天买入,然后同样在第i天卖出(收益为0)。
    上面的算法中对于天数需要一次扫描,而每次要对交易次数进行递推式求解,所以时间复杂度是O(n*k),
    如果是最多进行两次交易,那么复杂度还是O(n)。空间上只需要维护当天数据皆可以,所以是O(k),当k=2,则是O(1)。
Best Time to Buy and Sell Stock – LintCode