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

本文介绍了一种求解最长递增子序列问题的高效算法,使用了NlogN的时间复杂度。通过一个简洁的C++实现示例,展示了如何利用upper_bound函数寻找最合适的元素进行替换,从而得到最终的最长递增子序列长度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一般的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;
}
### 头歌平台中的最长上升子序列实现 在头歌平台上,可以通过多种编程语言实现最长上升子序列(Longest Increasing Subsequence, LIS)问题。以下是基于动态规划(Dynamic Programming, DP)和优化后的O(n log n)算法的两种常见方法。 #### 动态规划解法 动态规划是一种解决LIS的经典方法。定义`f[i]`表示以第i个元素结尾的最长上升子序列长度,则状态转移方程如下: - 如果存在某个位置j使得`a[j] < a[i]`,那么更新`f[i] = max(f[i], f[j] + 1)`[^3]。 最终的结果为数组`f[]`的最大值。这种方法的时间复杂度为O(),适用于较小规模的数据集。 ```python def lis_dp(arr): if not arr: return 0 n = len(arr) dp = [1] * n # 初始化dp数组,每个元素至少可以单独构成一个子序列 for i in range(1, n): # 遍历每一个元素作为结束点 for j in range(i): # 查找前面所有可能的小于当前元素的位置 if arr[j] < arr[i]: dp[i] = max(dp[i], dp[j] + 1) # 更新最大长度 return max(dp) # 返回整个数组中最长上升子序列长度 ``` #### O(n log n)解法 为了提高效率,可以采用贪心加二分查找的方法。维护一个辅助数组`d[]`,其中存储的是当前已知的最小末尾元素对应的上升子序列长度。具体操作如下: - 对于每个新加入的元素`a[i]`,如果其大于`d[]`中所有的数,则将其追加到`d[]`后面; - 否则,在`d[]`中通过二分查找找到第一个小于等于它的数,并替换掉下一个更大的数[^4]。 此方法能够显著降低时间复杂度至O(n log n)。 ```python import bisect def lis_nlogn(arr): d = [] # 辅助数组用于记录最优路径上的最小值 for num in arr: pos = bisect.bisect_left(d, num) # 找到num应该插入的位置 if pos >= len(d): # 若超出范围,则扩展列表 d.append(num) else: # 替换已有元素以保持更优的选择 d[pos] = num return len(d) # 最终d的长度即为所求LIS长度 ``` 以上两段代码分别展示了如何利用同的策略解决问题。可以根据实际需求选择合适的方式进行编码练习。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值