🚀 算法题 🚀 |
🌲 算法刷题专栏 | 面试必备算法 | 面试高频算法 🍀
🌲 越难的东西,越要努力坚持,因为它具有很高的价值,算法就是这样✨
🌲 作者简介:硕风和炜,CSDN-Java领域新星创作者🏆,保研|国家奖学金|高中学习JAVA|大学完善JAVA开发技术栈|面试刷题|面经八股文|经验分享|好用的网站工具分享💎💎💎
🌲 恭喜你发现一枚宝藏博主,赶快收入囊中吧🌻
🌲 人生如棋,我愿为卒,行动虽慢,可谁曾见我后退一步?🎯🎯
🚀 算法题 🚀 |
🍔 目录
- 🚗 知识回顾
- 🚩 题目链接
- ⛲ 题目描述
- 🌟 求解思路&实现代码&运行结果
- ⚡ 动态规划 + 二分查找
- 🥦 求解思路
- 🥦 实现代码
- 🥦 运行结果
- 💬 共勉
🚗 知识回顾
大家再看这道题目之前,可以先去看一下我之前写过的一篇关于最长递增子序列算法题的博客,再看这个题目就更容易理解了。
博客的地址放到这里了,可以先去学习一下这到题目。
- 【LeetCode: 300. 最长递增子序列 | 暴力递归=>记忆化搜索=>动态规划】
🚩 题目链接
- 牛客网:最长上升子序列(三)
⛲ 题目描述
给定数组 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)
🌟 求解思路&实现代码&运行结果
⚡ 动态规划 + 二分查找
🥦 求解思路
- 核心的求解思路我们之前都讲过了,此处就不做过多的讲解了,如果还有问题的同学可以看一下我之前的文章先进行学习,否则还是比较难理解的。
【LeetCode: 300. 最长递增子序列 | 暴力递归=>记忆化搜索=>动态规划】 - 那我们就着重来看一下该题想让我们求解什么?其实题目都告诉我们了,收集最长递增子序列结果的答案数组。
- 该题难在哪里?该题难就难在题目必须让我们通过动态规划+二分优化来求解,因为题目给定的数据量很大,如果不使用二分进行优化的话是通过不了的。
- 该题目怎么实现呢?1.原来基础的思路上再维护一个数组,用来表示以某一个位置结尾的最长递增子序列的长度;2.为保证字典序最小,从后开始向前遍历进行收集答案的过程。
- 有了基本的思路+前面题目的讲解,我们再来看这道题目就会感觉非常容易了,接下来我们一起来看具体代码的实现过程。
🥦 实现代码
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;
}
}
🥦 运行结果
💬 共勉
最后,我想和大家分享一句一直激励我的座右铭,希望可以与大家共勉! |