【经典面试题目:最长递增子序列变形题目 | 动态规划 + 二分】

本文介绍了如何使用动态规划结合二分查找解决牛客网上的最长上升子序列问题,详细阐述了求解思路,提供了解决代码,并强调了空间和时间复杂度的要求。通过实例解析,帮助读者理解算法的应用。

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

在这里插入图片描述

🚀 算法题 🚀

🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀
🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨
🌲 作者简介:硕风和炜,优快云-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎
🌲 恭喜你发现一枚宝藏博主,赶快收入囊中吧🌻
🌲 人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?🎯🎯

🚀 算法题 🚀

在这里插入图片描述

🚗 知识回顾

大家再看这道题目之前,可以先去看一下我之前写过的一篇关于最长递增子序列算法题的博客,再看这个题目就更容易理解了。
博客的地址放到这里了,可以先去学习一下这到题目。

🚩 题目链接

⛲ 题目描述

给定数组 arr ,设长度为 n ,输出 arr 的最长上升子序列。(如果有多个答案,请输出其中 按数值(注:区别于按单个字符的ASCII码值)进行比较的 字典序最小的那个)

数据范围:
0≤n≤200000,0≤arr[i]≤1000000000
要求:空间复杂度 O(n),时间复杂度 O(nlogn)

输入:
[1,2,8,6,4]

返回值:
[1,2,4]

说明:
其最长递增子序列有3个,(1,2,8)、(1,2,6)、(1,2,4)其中第三个 按数值进行比较的字典序 最小,故答案为(1,2,4)

🌟 求解思路&实现代码&运行结果


⚡ 动态规划 + 二分查找

🥦 求解思路
  1. 核心的求解思路我们之前都讲过了,此处就不做过多的讲解了,如果还有问题的同学可以看一下我之前的文章先进行学习,否则还是比较难理解的。
    【LeetCode: 300. 最长递增子序列 | 暴力递归=>记忆化搜索=>动态规划】
  2. 那我们就着重来看一下该题想让我们求解什么?其实题目都告诉我们了,收集最长递增子序列结果的答案数组。
  3. 该题难在哪里?该题难就难在题目必须让我们通过动态规划+二分优化来求解,因为题目给定的数据量很大,如果不使用二分进行优化的话是通过不了的。
  4. 该题目怎么实现呢?1.原来基础的思路上再维护一个数组,用来表示以某一个位置结尾的最长递增子序列的长度;2.为保证字典序最小,从后开始向前遍历进行收集答案的过程。
  5. 有了基本的思路+前面题目的讲解,我们再来看这道题目就会感觉非常容易了,接下来我们一起来看具体代码的实现过程。
🥦 实现代码
import java.util.*;


public class Solution {
    /**
     * retrun the longest increasing subsequence
     * @param arr int整型一维数组 the array
     * @return int整型一维数组
     */
    public int[] LIS (int[] arr) {
        int n=arr.length;
        // dp 数组中存储的是单调递增的元素
        int[] dp=new int[n];
        int cnt=0;
        // len 数组表示以i位置结尾的最长递增子序列的长度
        int[] len=new int[n];
        for(int i=0;i<n;i++){
            int x=arr[i];
            int left=-1,right=cnt;
            while(left+1<right){
                int mid=(left+right)>>1;
                if(dp[mid]<x){
                    left=mid;  
                }else{
                    right=mid;
                }
            }
            dp[right]=x;
            // 记录当前i位置下标最长递增子序列的长度   长度要加1,下标从0开始
            len[i]=right+1;
            if(right==cnt) cnt++;
        }
        // 收集答案
        int[] ans=new int[cnt];
        for(int i=n-1;i>=0;i--){
            if(len[i]==cnt){
                ans[--cnt]=arr[i];
            }
        }
        return ans;
    }
}
🥦 运行结果

在这里插入图片描述


💬 共勉

最后,我想和大家分享一句一直激励我的座右铭,希望可以与大家共勉!

在这里插入图片描述

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

硕风和炜

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值