【算法筆記】動態(tài)規(guī)劃:最長遞增子序列

Input

10 9 2 5 3 7 101 18

Output

4 (因為2,3,7,101是最長的遞增子序列)

解題思路

該問題滿足最優(yōu)子結(jié)構(gòu)性質(zhì),因此可以使用動態(tài)規(guī)劃求解。

定義如下符號:

  • n表示問題序列的總長度。
  • A[1:i]表示下標從1到i的一個序列,特別地,A[1:n]表示下標從1開始,長度為n的一個序列,也就是問題的輸入。
  • A_i表示A[1:n]中的第i個元素。

由于問題的最優(yōu)解必然對應(yīng)某個子序列,而這個子序列又必然由某個A_i結(jié)尾,因此,由所有A_i結(jié)尾的最長遞增序列的長度,構(gòu)成了問題的解空間。因此,再引入符號L,來描述問題的解空間:

  • L_i表示以A_i結(jié)尾的最長遞增子序列的長度。

顯然,A_i為該遞增子序列的最大值,\max (L_i)就是問題的最優(yōu)解。

求解\max (L_i),就要得到所有的L_i。求解L_i這一問題,包含了求解從L_{1}L_{i-1}的所有子問題,從而滿足最優(yōu)子結(jié)構(gòu)性質(zhì)。

遞歸方程如下:

L_k=\begin{cases} 1, & {\forall} i\in [1,k), A_k\leqslant A_i\\ \max(L_i)+1|i\in [1,k), A_k> A_i , & \exists i\in [1,k), A_k> A_i \end{cases}

轉(zhuǎn)換成代碼,思路就是遍歷所有A_i,選擇滿足A_k>A_i的最大的L_i,則L_k=L_i+1,如果A_k比所有A_i都要小,則L_k=1


完整代碼

Leetcode上面有這個問題,可以上去檢驗一下:

class Solution {
public:

int max(const int &a, const int &b)
{
    return a>b?a:b;
}
int lengthOfLIS(vector<int> &nums)
{
    int n = nums.size();
    int res = 1;
    if(nums.size() == 0) return 0;
    
    int *l = new int[n];
    l[0] = 1;
    
    for(int i = 1; i < n; i++)  //填充L
    {
        int maxval = 1;
        for(int j = 0; j < i; j++)  //遍歷所有的A
        {
            if(nums[i] > nums[j])
            {
                maxval = max(maxval, l[j]+1);
            }
            l[i] = maxval;
        }
    }
    
    for(int i = 0; i < n; i++)
    {
        if(l[i]>res)
        {
            res = l[i];
        }
    }
    return res;
}

};

參考資料:https://www.zhihu.com/question/23995189

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

推薦閱讀更多精彩內(nèi)容