leetcode 300. 最长上升子序列(NlogN)

给定一个无序整数数组,求最长上升子序列的长度。例如,在输入数组 [10, 9, 2, 5, 3, 7, 101, 18] 中,最长上升子序列是 [2, 3, 7, 101],长度为 4。进阶挑战是将算法时间复杂度降至 O(n log n)。解决方案包括使用单调递增的dp数组,通过二分查找找到合适位置更新dp值。" 127167622,1437049,Linux后台运行命令:nohup、&及进程查询,"['Linux运维', '服务器管理', '命令行工具']

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

给定一个无序的整数数组,找到其中最长上升子序列的长度。

示例:

输入: [10,9,2,5,3,7,101,18]
输出: 4
解释: 最长的上升子序列是 [2,3,7,101],它的长度是 4。
说明:

可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
你算法的时间复杂度应该为 O(n2) 。
进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

经典题,N平方算法不再赘述,简单说一说NlogN算法。

令dp[i]表示长度为i的递增子序列结尾的最小值,显然这个dp[i]是随着i的增大而逐渐变大的,下面举个例子说明。

[10,9,2,5,3,7,101,18]这组样例,遍历数组,当遍历到nums[1] = 10时,dp[1] = 10,当nums[2] = 9时,那么dp[1] = 9,注意这里是dp[1]而不是dp[2],因为num[2]之前找不到一个值比9小,以此类推即可。

很容易可以看出,以上步骤可以总结为当遍历到第k位,要找到最后一个比num[k]小的dp[i],然后dp[i+1] = min(dp[i+1],num[k]),由于dp数组单调递增,所以找最后一个比num[k]小的值可以用二分去写。

class Solution {
    public int lengthOfLIS(int[] nums) {
        int len = nums.length;
        int num[] = new int [len+1];
        for(int i=0;i<len;i++)
        {
            num[i+1] = nums[i];
        }
        int dp[] = new int [len+1];
        for(int i=1;i<=len;i++)
            dp[i] = 0x3f3f3f3f;
        dp[0] = -0x3f3f3f3f;
        for(int i=1;i<=len;i++)
        {
            int l = 0;
            int r = len;
            while(l<=r)
            {
                int mid = (l+r)/2;
                if(dp[mid]<num[i])
                    l = mid + 1;
                else
                    r = mid - 1;
            }
            dp[l] = Math.min(num[i],dp[l]);
        }
        for(int i=len;i>=0;i--)
        {
            if(dp[i]<0x3f3f3f3f)
                return i;
        }
        return 1;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值