最长不上升子序列的优化(nlogn)

一般的DP写法:

    for (int i=1;i<=t;i++)
        {
            f[i]=1;
            for (int j=1;j<i;j++)
            if (num[i]>num[j]&&f[j]+1>f[i])
                f[i]=f[j]+1;
        }
    int max=0;
    for (int i=1;i<=t;i++)if (f[i]>max) max=f[i];

看到http://www.cnblogs.com/itlqs/p/5743114.html有个简洁的nlogn写法 学习一下.

#include<cstdio>
#include<algorithm>
using namespace std;

int a[40005];
int d[40005];

int main()
{
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    if (n==0)  //0个元素特判一下 
    {
        printf("0\n");
        return 0;
    }
    d[1]=a[1];  //初始化 
    int len=1;
    for (int i=2;i<=n;i++)
    {
        if (a[i]>=d[len]) d[++len]=a[i];  //如果可以接在len后面就接上 
        else  //否则就找一个最该替换的替换掉 
        {
            int j=upper_bound(d+1,d+len+1,a[i])-d;  //找到第一个大于它的d的下标 
            d[j]=a[i]; 
        }
    }
    printf("%d\n",len);    
    return 0;
}
### 回答1: 最长上升子序列(Longest Increasing Subsequence, LIS)是指一个序列中最长的严格递增子序列的长度。以下是 C++ 实现 LIS 的示例代码: ```c++ #include <iostream> #include <algorithm> #include <vector> using namespace std; int main() { vector<int> nums = {10, 9, 2, 5, 3, 7, 101, 18}; vector<int> dp(nums.size(), 1); // dp[i] 表示以 nums[i] 结尾的最长上升子序列长度 int res = 1; // 记录最大长度 for (int i = 1; i < nums.size(); i++) { for (int j = 0; j < i; j++) { if (nums[j] < nums[i]) { dp[i] = max(dp[i], dp[j] + 1); // 状态转移方程 } } res = max(res, dp[i]); } cout << res << endl; // 输出最长上升子序列长度 return 0; } ``` 该代码的时间复杂度为 O(n^2),可以通过二分查找优化到 O(nlogn)。 ### 回答2: 最长上升子序列(Longest Increasing Subsequence)是指在一个给定序列中,找出一个最长子序列使得子序列中的元素按照顺序递增。给定一个长度为n的序列A,最长上升子序列的长度可以通过动态规划的方法求解。 假设dp[i]表示以第i个元素结尾的最长上升子序列的长度,那么状态转移方程可以定义为: dp[i] = max(dp[j] + 1), 其中0 <= j < i,A[j] < A[i] 首先,初始化dp数组为1,表示每个元素本身就构成一个长度为1的最长上升子序列。 然后,从左往右遍历数组A,对于每个元素A[i],遍历之前的所有元素A[j](j<i),如果A[j] < A[i],则更新dp[i]为dp[j]+1。 最后,返回dp数组中的最大值即为最长上升子序列的长度。 举个例子,给定序列A=[3, 10, 2, 1, 20],首先初始化dp数组为[1, 1, 1, 1, 1]。 遍历到元素10时,与3比较,满足条件A[j] < A[i],更新dp[1]为dp[0]+1,得到dp=[1, 2, 1, 1, 1]。 再遍历到元素2时,与3和10比较,均不满足条件,不更新dp数组,得到dp=[1, 2, 1, 1, 1]。 继续遍历到元素1时,与3、10和2比较,满足条件A[j] < A[i],更新dp[3]为dp[2]+1,得到dp=[1, 2, 1, 2, 1]。 最后遍历到元素20时,与3、10、2和1比较,均满足条件,更新dp[4]为dp[3]+1,得到dp=[1, 2, 1, 2, 3]。 返回dp数组中的最大值3,即为最长上升子序列的长度。 综上所述,利用动态规划可以求解最长上升子序列的长度。 ### 回答3: 最长上升子序列(Longest Increasing Subsequence,LIS)是指在一个给定序列中,找到一个最长子序列,使得这个子序列中的元素按照严格递增的顺序排列。 设序列为a[1…n],定义dp[i]为以a[i]结尾的LIS的长度。那么转移方程可以表示为:dp[i] = max{dp[j] + 1 | 1 ≤ j < i, a[j] < a[i]}。 根据状态转移方程,我们需要遍历所有小于i的j,找到能够构成最长上升子序列的j,从而更新dp[i]。可以使用动态规划的思路,通过一个辅助数组dp来记录每个位置的最长上升子序列长度。 具体实现上,我们可以使用两个循环来遍历序列a,外层循环从1到n,内层循环从1到i。在内层循环中,比较a[j]和a[i]的大小,若满足条件则更新dp[i]为较大值。 最后,我们只需要遍历dp数组中的最大值,即为最长上升子序列的长度。 例如,对于序列c = [1, 3, 5, 2, 4, 6, 7],通过使用动态规划的方法,我们可以得到dp = [1, 2, 3, 2, 3, 4, 5]。最长上升子序列的长度为5。 最长上升子序列问题是一个经典的动态规划问题,它的时间复杂度为O(n^2)。同时,还存在更优化的解法,比如使用二分查找加速查找过程,将时间复杂度优化为O(nlogn)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值