【动态规划专题】7:最长递增子序列

《程序员代码面试指南--IT名企算法与数据结构题目最优解》 左程云 著

最长递增子序列

【题目】
给定数组arr,返回arr的最长递增子序列

【举例】
arr=[2,1,5,3,6,4,8,9,7],返回的最长递增子序列为[1,3,4,8,9]

【要求】
如果arr长度为N,请实现时间复杂度为O(NlogN)的方法

#include <iostream>
#include <vector>
#include <algorithm>
#include <stdlib.h>
using namespace std;


void Printdp(int ** dp, int rows, int cols)
{
    cout << "Printdp--------------start" << endl;
    for (int i = 0; i < rows; i++)
    {
        for (int j = 0; j < cols; j++)
        {
            cout << dp[i][j] << ",";
        }
        cout << endl;
    }
    cout << "Printdp--------------End" << endl;
    cout << endl;
}

int MaxNum(int A, int B)
{
    if (A > B)
    {
        return A;
    }
    else
    {
        return B;
    }
}
void generateLIS(int *arr, int length, int* dp)
{
    int len = 0;
    int index = 0;
    for (int i = 0; i < length; i++)
    {
        if (dp[i]>len)
        {
            len = dp[i];
            index = i;
        }
    }

    int *outlist = new int[len];
    int iOutIndex = len;
    outlist[--iOutIndex] = arr[index];
    for (int i = index; i >= 0; i--)
    {
        if (arr[i] < arr[index] && dp[i] == dp[index] - 1)
        {
            outlist[--iOutIndex] = arr[i];
            index = i;
        }
    }

    /////output result
    cout << "<<<<<< output result >>>>>" << endl;
    for (int i = 0; i < len; i++)
    {
        cout << outlist[i] << ",";
    }
    cout << endl;
}
/////这种获取dp数组的时间复杂度为O(N^2)
void getdp1(int* arr, int length, int *dp )
{
    for (int i = 0; i < length; i++)
    {
        dp[i] = 1;
        for (int j = 0; j < i; j++)
        {
            if (arr[j] < arr[i])
            {
                dp[i] = MaxNum(dp[i], dp[j] + 1);
            }
        }
    }

    cout << "dp------------print" << endl;
    for (int i = 0; i < length; i++)
    {
        cout << dp[i] << ", ";
    }
    cout << endl;
}


void list1(int *arr, int length)
{
    if (arr == nullptr || length <= 0)
    {
        return ;
    }

    int* dp = new int[length];

    getdp1(arr, length, dp);
    generateLIS(arr, length, dp);
}
/////////////////////////////////////////////////////对getdp函数做优化
////二分查找,将时间复杂度降为了 O(NlogN) 
void getdp2(int* arr, int length, int *dp)
{
    int* ends = new int[length];
    ends[0] = arr[0];
    dp[0] = 1;
    int right = 0;
    int L = 0;
    int R = 0;
    int M = 0;
    for (int i = 1; i < length; i++)
    {
        L = 0;
        R = right;

        /////二分查找
        while (L <= R)
        {
            M = (L + R) / 2;
            if (arr[i]>ends[M])
            {
                L = M + 1;
            }
            else
            {
                R = M - 1;
            }
        }

        right = MaxNum(right, L);
        ends[L] = arr[i];
        dp[i] = L + 1;


        /////////////////////////////////////////////
        cout << "ends["<<i<<"]: ";
        for (int k = 0; k < i; k++)
        {
            cout << ends[k] << ",";
        }
        cout << endl << endl;
        cout << "dp[" << i << "]: ";
        for (int k = 0; k < i; k++)
        {
            cout << dp[k] << ",";
        }
        cout << endl <<"---->>>>>>><<<<<<<<--------"<< endl;
        int abcde = 0;
    }


    cout << "dp------------print" << endl;
    for (int i = 0; i < length; i++)
    {
        cout << dp[i] << ", ";
    }
    cout << endl;
}


void list2(int *arr, int length)
{
    if (arr == nullptr || length <= 0)
    {
        return;
    }

    int* dp = new int[length];

    getdp2(arr, length, dp);
    generateLIS(arr, length, dp);
}
////===============测试用例====================
void test1()
{
    int arr[] = { 2, 1, 5, 3, 6, 4, 8, 9, 7 };
    //list1(arr, sizeof(arr) / sizeof(int));

    list2(arr, sizeof(arr) / sizeof(int));
}

void test2()
{
    int arr[] = {12, 122, 2, 1, 3,5,7,101,102,103,9,11,104,105,12,15,17,20,100,200};
    list1(arr, sizeof(arr) / sizeof(int));

    list2(arr, sizeof(arr) / sizeof(int));///error
}


void test3()
{
    int arr[] = { 1, 2, 3, 4, 5, 6, 7, 8 };
    list1(arr, sizeof(arr) / sizeof(int));

    list2(arr, sizeof(arr) / sizeof(int));
}

void test4()
{
    int arr[] = { 7,6,5,4,3,2,1 };
    list1(arr, sizeof(arr) / sizeof(int));
    list2(arr, sizeof(arr) / sizeof(int));
}
int main()
{
    test1();
    test2();
    test3();
    test4();


    cout << endl;
    system("pause");
    return 0;
}

算法思考:

getdp1(), getdp2(),这2中获取 dp[ ]  数组 的方式,非常值得思考和借鉴。

原文地址:https://www.cnblogs.com/music-liang/p/12145440.html