最長上升子序列問題LIS

問題描述(poj2533):對於給定的n個整數A1, A2…An, 從左到右的順序選擇儘可能多的數,組成一個上升子序列。(上升子序列可以理解爲:刪除0個或多個數, 其他數的順序不變, 例如1, 6, 2, 3, 7, 5, 可以選出上升子序列1, 2, 3, 5 也可以選出 1, 6, 7)
poj2533 : 求最長上升子序列的長度
法一:通過DP記憶化搜索求解問題,時間複雜度爲O(n^2)

#include<iostream>
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<string>
#include <algorithm>
using namespace std;

int n, m, i, j, mx;
const int maxn = 1010;
int a[maxn], d[maxn];

//記憶化搜索
//狀態:d[i]:第i個數的最長子序列的長度
//狀態轉移爲d[i] = max(d[i], d[j] + 1);
int main()
{
    while(~scanf("%d",&n)){              //共有n個數
        for(i = 0; i < n;i++)           //錄入n個數保存在數組a[]中
            scanf("%d",&a[i]);
        for (i = 0; i < n; i++)
        {
            d[i] = 1;                              //初始化數組d[]爲1,
            for(j = 0;j < i;j++)
                if(a[j] < a[i])
                    d[i] = max(d[i], d[j] + 1); //第i個數的最長子序列長度 等於 比 第i個數小 的 數的最長子序列加1
        }
        mx = 0;
        for(i = 0;i < n;i++)
            mx = max (mx ,d[i]);
        printf("%d\n",mx);
    }
    return 0;
}

法二:用DP二分搜索解決問題降低時間複雜度,該方法的時間複雜度爲O(nlogn)
實現:開一個棧,每次取棧頂元素top和讀到的元素temp做比較,如果temp > top 則將temp入棧;如果temp < top則二分查找棧中的比temp大的第1個數,並用temp替換它。 最長序列長度即爲棧的大小top。
舉例:原序列爲1,5,8,3,6,7

棧爲1,5,8,此時讀到3,用3替換5,得到1,3,8; 再讀6,用6替換8,得到1,3,6;再讀7,得到最終棧爲1,3,6,7。最長遞增子序列爲長度4。
如果想要輸出最長有序子數列的話,可以在法二的基礎上稍作改動。
用一個b【i】記錄第i個元素在隊列中的位置,然後逆向尋找,依次輸出。

//二分搜索
#include <iostream>
#define SIZE 1001

using namespace std;

int main()
{
    int i, j, n, top, temp;
    int stack[SIZE];
    cin >> n;

    top = 0;
    stack[0] = -1;//令棧頂元素爲-1
    for (i = 0; i < n; i++)
    {
        cin >> temp;
        /* 比棧頂元素大數就入棧 */
        if (temp > stack[top])
        {
            stack[++top] = temp;
        }
        else
        {
            int low = 1, high = top;
            int mid;
            /* 二分檢索棧中比temp大的第一個數 */
            while (low <= high)
            {
                mid = (low + high) / 2;
                if (temp > stack[mid])
                {
                    low = mid + 1;
                }
                else
                {
                    high = mid - 1;
                }
            }
            /* 用temp替換 */
            stack[low] = temp;
        }
    }

    /* 最長序列數就是棧的大小 */
    cout << top << endl;

    //system("pause");
    return 0;
}

發佈了47 篇原創文章 · 獲贊 6 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章