LeetCode 188 - Best Time to Buy and Sell Stock IV 解題心得( 題目 )

解題概念:DP、Aliens 優化

解題方法:這題不難,原因是他n、k很小,我們可以假設兩個陣列:

解法(1):二維DP,時間複雜度:O(nk)

dp0[i][j]代表目前不持有,討論時間點i之前進行最多j交易的最佳解。

dp1[i][j]則代表目前持有,討論時間點i之前進行最多j交易的最佳解。

列一下轉移式即可以O(nk)解決(下面假設v[i]代表在i時的價格):

dp0[i][j]=max(dp1[i-1][j-1]+v[i],dp0[i-1][j])

dp1[i][j]=max(dp0[i-1][j]-v[i],dp1[i-1][j])

但是這次為何會想解這題,原因是其實早在好幾個月前早就看過一模一樣的題目,那時我完全沒想法(連nk解法都沒有),但現在看發現以前那題n、k很大,可以都超過10^5,所以顯然需要另一種解法。

解法(2):一維DP+Aliens 優化,時間複雜度:O(nlogC)

這個解法可以忽視k大小,由於k和解大小的關係函數具凸性,所以可以使用Aliens優化,在每次DP假設一個penalty,代表每次交易的費用,透過二分搜penalty找到符合題意剛好k次的penalty,最後再把它加回去。

令dp[i]=pair(j,k)代表在時間點i之前最大值是j而需要k次交易

轉移式變成如下:

dp0[i]=max(dp1[i-1]+v[i]+額外費用,dp0[i-1])

dp1[i]=max(dp0[i-1]-v[i](買賣次數+1),dp1[i-1])

class Solution {

    int l,r,m;//for BIS , m -> penalty

    int ans,k,leng;

    int[] v=new int[1005];

    pair[] dp0=new pair[1005];//for DP

    pair[] dp1=new pair[1005];

    public int maxProfit(int k, int[] prices) {

        this.k=k;

        leng=prices.length;

        init(prices);

        return BIS();

    }

    

    public void init(int[] p) {

        ans=-1;

        l=-1005;

        r=1005;

        Arrays.fill(v,0);

        for(int i=0;i<1005;i++)dp0[i]=new pair();

        for(int i=0;i<1005;i++)dp1[i]=new pair();
        
            for(int i=1;i<=leng;i++)v[i]=p[i-1];

        dp0[0].x=0;

        dp0[0].y=0;

        dp1[0].x=-(1<<30);

        dp1[0].y=0;

    }

    

    public pair max(pair f,pair s) {

        if(f.x!=s.x)return (f.x>s.x)?f:s;

        return (f.y>s.y)?f:s;

    }

    

    public pair buy(pair f,int val) {

        return new pair(f.x-val+m,f.y);

    }

    

    public pair sell(pair f,int val) {

        return new pair(f.x+val,f.y+1);

    }

    

    public pair DP() {

        for(int i=1;i<=leng;i++) {

            dp1[i]=max(dp1[i-1],buy(dp0[i-1],v[i]));

            dp0[i]=max(dp0[i-1],sell(dp1[i-1],v[i]));

        }

        return dp0[leng];         

    }

    

    public int BIS() {

        pair dp;

        while(l!=r) {

            m=(l+r)>>1;//Penalty Binary Search

            dp=DP();

            if(dp.y<k) {

                l=m+1;

                ans=Math.max(ans,dp.x-m*(dp.y));

            }

            else r=m;    

        }

        m=l;

        return Math.max(ans,DP().x-m*k);

    }

}



class pair{

    int x=0,y=0;

    pair(){}

    pair(int a,int b){

        x=a;

        y=b;

    }

}

 

 

 

 

文章標籤
全站熱搜
創作者介紹
創作者 En Chi Tsung 的頭像
En Chi Tsung

阿祁的部落格

En Chi Tsung 發表在 痞客邦 留言(0) 人氣(14)