• 最长递增子序列(Longest increasing subsequence)


    问题定义:

        给定一个长度为N的数组A,找出一个最长的单调递增子序列(不要求连续)。

        这道题共3种解法。

    1. 动态规划

        动态规划的核心是状态的定义和状态转移方程。定义lis(i),表示前i个数中以A[i]结尾的最长递增子序列的长度。可以得到以下的状态转移方程:

    d(i) = max(1, d(j) + 1), 其中j < i,且A[j] <= A[i]

    程序实现:

    int longestIncreasingSubsequence(vector<int> nums)
    {
        if (nums.empty())
            return 0;
        int len = nums.size();
        vector<int> lis(len, 1);    
    
        for (int i = 1; i < len; ++i)
        {
            for (int j = 0; j < i; ++j)
            {
                if (nums[j] < nums[i] && lis[i] < lis[j] + 1)
                    lis[i] = lis[j] + 1;
            }
        }
        return *max_element(lis.begin(), lis.end());
    }

    程序复杂度为O(N^2)

    2. 动态规划 + 二分查找

        换一种角度看问题。令Ai,j表示所有长度为j的最大递增子序列的最小末尾,我们有Ai,1 < Ai,2 < ... < Ai,j。

    对A[i+1]来说,有两种选择。

    1. Ai,j < A[i+1], 此时我们可以得到一个长度为i+1的最大递增子序列。

    2. 替换Ai,k,如果Ai,k-1 < A[i+1] < Ai,k。

    替换长度为k的最大递增子序列的最小末尾,是为了增大获取更长子序列的机会。

    程序实现:

    int binarySearch(const int arr[], int low, int high, int val)
    {
        while (low <= high)
        {
            int mid = low + (high - low) / 2;    // Do not use (low + high) / 2 which might encounter overflow issue
    
            if (val < arr[mid])
                high = mid - 1;
            else if (val > arr[mid])
                low = mid + 1;
            else
                return mid;
        }
        return low;
    }
    int LIS(int arr[], int n)
    {
        int *minTail = new int[n];
        minTail[0] = arr[0];
        int len = 1;
        for (int i = 1; i < n; ++i)
        {
            if (arr[i] > minTail[len-1])
                minTail[len++] = arr[i];
            else
            {
                int pos = binarySearch(minTail, 0, len-1, arr[i]);
                minTail[pos] = arr[i];
            }
        }
        delete [] minTail;
        return len;
    }

    复杂度:O(nlogn)

    reference : 

    最长递增子序列(LIS)

    3. 排序+LCS

        这种方法就不细说了。。。

  • 相关阅读:
    实现多页签切换效果
    CSS样式display:none和visibility:hidden的区别
    canvas主要属性和方法
    Web前端的35个jQuery小技巧
    div+css3实现的小丸子和爷爷
    Jquery实现手机上下滑屏滑动的特效代码
    使用phantomjs生成网站快照
    VSCode配置Go language tools
    TypeScript中慎用forEach
    win8开发之数据绑定控件Gridview以分组及不同项模板的形式呈现数据
  • 原文地址:https://www.cnblogs.com/gattaca/p/4724778.html
Copyright © 2020-2023  润新知