LintCode领扣 题解丨字节跳动高频题:最长上升子序列

简介: LintCode领扣 题解丨字节跳动高频题:最长上升子序列

给定一个整数序列,找到最长上升子序列(LIS),返回LIS的长度。

在线评测地址:
https://www.lintcode.com/problem/longest-increasing-subsequence/description?utm_source=sc-tianchi-sz0828

说明

最长上升子序列的定义:

最长上升子序列问题是在一个无序的给定序列中找到一个尽可能长的由低到高排列的子序列,这种子序列不一定是连续的或者唯一的。


样例 1:

输入:  [5,4,1,2,3]
输出:  3

解释:
LIS 是 [1,2,3]

样例 2:

输入: [4,2,4,5,3,7]
输出:  4

解释: 
LIS 是 [2,4,5,7]

算法:动态规划(dp)
算法思路

因为所求为子序列,很容易想到一种线性动态规划。
对于求最长上升子序列,上升我们肯定需要知道当前阶段最后一个元素为多少,最长我们还要知道当前我们的序列有多长。
那么我们就可以这样定义状态:设 dp[i] 表示以 nums[i] 为结尾的最长上升子序列的长度,为了保证元素单调递增肯定只能从 i 前面且末尾元素比 nums[i] 小的状态转移过来
代码思路

状态转移方程为

每个位置初始值为 dp[i]=1(将自己作为一个序列)
答案可以是任何阶段中只要长度最长的那一个,所以我们边转移边统计答案
复杂度分析

N表示为nums 的长度

空间复杂度:O(N)
时间复杂度:O(N^2)
public class Solution {

/**
 * @param nums: The integer array
 * @return: The length of LIS (longest increasing subsequence)
 */
public int longestIncreasingSubsequence(int[] nums) {
    // dp[i]表示以nums[i]为结尾的最长上升子序列的长度
    int []dp = new int[nums.length];
    int ans = 0;
    for (int i = 0; i < nums.length; i++) {
        // 初始值为1
        dp[i] = 1;
        for (int j = 0; j < i; j++) {
            if (nums[j] < nums[i]) {
                // 若nums[j] < nums[i]那么可以接在该序列后,更新状态
                dp[i] = dp[i] > dp[j] + 1 ? dp[i] : dp[j] + 1;
            }
        }
        // 记录所有状态中的最大值
        if (dp[i] > ans) {
            ans = dp[i];
        }
    }
    return ans;
}

}
优化算法:动态规划(dp)+二分优化
上面说过:我们肯定要知道当前阶段最后一个元素为多少,还有当前的序列有多长。上面的方法是用前者做状态,即元素是多少,那么我们可不可以用后者,即序列长度做状态呢?

算法思路

设 dp[i] 表示长度为 i 的最长上升子序列的末尾元素的最小值,显然这个数组的权值一定单调不降。
于是我们按顺序枚举数组nums,每一次对dp数组二分查找,找到小于nums[i]的最大的 dp[j],并更新 dp[j+1]。
复杂度分析

空间复杂度:O(N)
时间复杂度:O(NlogN)
public class Solution {

/**
 * @param nums: An integer array
 * @return: The length of LIS (longest increasing subsequence)
 */
public int longestIncreasingSubsequence(int[] nums) {
    if (nums == null || nums.length == 0) {
        return 0;
    }
    
    int[] lis = new int[nums.length + 1];
    lis[0] = Integer.MIN_VALUE;
    for (int i = 1; i <= nums.length; i++) {
        lis[i] = Integer.MAX_VALUE;
    }
    
    int longest = 0;
    for (int i = 0; i < nums.length; i++) {
        int index = firstGTE(lis, nums[i]);
        lis[index] = nums[i];
        longest = Math.max(longest, index);
    }
    
    return longest;
}

// GTE = Greater Than or Equal to
private int firstGTE(int[] nums, int target) {
    int start = 0, end = nums.length - 1;
    while (start + 1 < end) {
        int mid = start + (end - start) / 2;
        if (nums[mid] >= target) {
            end = mid;
        } else {
            start = mid;
        }
    }
    if (nums[start] >= target) {
        return start;
    }
    return end;
}

}
更多题解参见九章算法官网:
https://www.jiuzhang.com/solution/longest-increasing-subsequence/?utm_source=sc-tianchi-sz0828

相关文章
|
域名解析 监控 算法
阿里云拨测:主动探测Web应用质量,助力提升用户体验
阿里云拨测是一种针对互联网应用(Web页面、网络链路等)进行应用性能和用户体验监测的服务,无需嵌码即可为云上用户提供开箱即用的企业级主动拨测式应用监测解决方案。
8771 111
阿里云拨测:主动探测Web应用质量,助力提升用户体验
|
SQL Oracle 关系型数据库
java往oracle存clob类型的值时,字符长度过长怎么办?
java往oracle存clob类型的值时,字符长度过长怎么办?
1482 1
|
并行计算 PyTorch 算法框架/工具
《 PyTorch 2.3革新:torch.compile自动生成CUDA优化内核全解》
torch.compile是PyTorch 2.3推出的革命性功能,通过即时编译(JIT)技术优化模型运行速度。它借助TorchDynamo提取计算图,并通过TorchInductor生成高度优化的CUDA内核,充分发挥GPU并行计算能力。支持默认、reduce-overhead和max-autotune三种模式,分别适用于不同性能需求场景。尽管在复杂模型或动态计算图中可能面临挑战,但通过调整参数或结合其他优化技术,仍可显著提升性能。这一工具极大简化了CUDA代码优化流程,为深度学习开发提供了强大支持。
828 10
|
3月前
|
人工智能 运维 安全
阿里云JVS Claw全面开放:零门槛云端 "养龙虾",免费体验 OpenClaw 时代来了!
阿里云JVS Claw是OpenClaw的云端SaaS版,JVS官网:https://t.aliyun.com/U/IJbaxg 免安装、免配置、免API密钥,提供6核CPU/12GB内存沙盒环境。新用户享7天全功能免费体验,支持多端同步、语音输入、定时任务与可视化管控,真正实现“零门槛养龙虾”。
|
8月前
|
人工智能 算法 安全
数字人平台指南:聚焦四大关键维度,破解选型难题
本文深度测评32款主流AI数字人平台,从技术性能、功能覆盖、使用体验、场景适配四大维度综合分析,助力用户科学决策。
|
5月前
|
人工智能 监控 网络安全
不想上班?让“OpenClaw”替你干活!帮你24小时开工!附秒级部署OpenClaw教程
每天清晨被闹钟叫醒,拖着疲惫的身躯奔赴工位,面对堆积如山的邮件、枯燥重复的报表、永无止境的信息整理,是不是无数次在心里默念“不想上班”?我们厌倦的从来不是工作本身,而是那些机械、琐碎、毫无创造性的重复劳动——明明几分钟就能说清的需求,却要花几小时手动执行;明明可以自动完成的流程,却要日复一日浪费时间精力。
2144 9
|
数据中心 网络虚拟化 云计算
|
9月前
|
机器学习/深度学习 人工智能
破译AI指纹:如何检测内容是否出自机器之手?
破译AI指纹:如何检测内容是否出自机器之手?
389 3
|
Linux 数据处理 Perl
深入探索Linux中的`more`命令
`more`命令是Linux下的文本查看器,适合查看长文件,分页显示内容,支持交互操作如空格(下一页)、回车(下一行)、q(退出)。参数包括:+&lt;num&gt;从指定行开始,/-&lt;num&gt;跳过行,/pattern搜索模式。示例:查看日志`more /var/log/syslog`,从第1000行开始`more +1000 file`,搜索关键词`more /var/log/syslog +/ERROR`。大文件可考虑使用`less`。结合`grep`等命令增强功能。
|
存储 开发工具 git
TortoiseSVN迁移到本地git
通过上述步骤,您可以将项目从TortoiseSVN迁移到本地Git仓库。这一过程包括从SVN仓库检出代码、使用 `git-svn`转换为Git仓库、优化Git仓库以及将本地仓库推送到远程Git仓库。以下是思维导图示例,帮助您更好地理解迁移过程。
1167 27