leetcode300---Longest Increasing Subsequence(最长递增子序列)
来源:互联网 发布:自助餐收银软件下载 编辑:程序博客网 时间:2024/04/29 14:54
问题描述:
Given an unsorted array of integers, find the length of longest increasing subsequence.
For example,
Given [10, 9, 2, 5, 3, 7, 101, 18],
The longest increasing subsequence is [2, 3, 7, 101]
, therefore the length is 4
. Note that there may be more than one LIS combination, it is only necessary for you to return the length.
Your algorithm should run in O(n2)
complexity.
Follow up: Could you improve it to O(n log n)
time complexity?
给定一个未经排序的整数数组,寻找最长递增子序列的长度。
问题求解:
方法一:动态规划。时间复杂度为O(n^2)。
状态转移方程:dp[i] = max{dp[j]+1,dp[i]}, j<i&&a[j]<a[i].
class Solution {public://动态规划。时间复杂度为O(n^2)。 int lengthOfLIS(vector<int>& nums) { int n=nums.size(); if(n <= 1) return n; vector<int> dp(n, 1); for(int i=1;i<n;i++) {//dp[i]表示LIS的长度。nums[i]作为LIS的最后一个元素。 for(int j=0;j<i;j++) { if(nums[i] > nums[j]) {//满足递增 dp[i]=max(dp[i], dp[j]+1);//利用状态转移方程 } } } int res=0; for(int i=0;i<n;i++) {//求得最大的dp[i] res = max(res, dp[i]); } return res; }};
方法二:贪心法+二分搜索!!!时间复杂度O(n * log n),空间复杂度O(n)!!!
设dp[i]表示以i为结尾的最长递增子序列的长度。考虑两个数a[x]和a[y],x < y且a[x] < a[y]
,且dp[x]=dp[y]
,当a[t]要选择时,到底取哪一个构成最优的呢?显然选取a[x]更有潜力,因为可能存在a[x]<a[z]<a[y]
,这样a[t]可以获得更优的值。在这里给我们一个启示,当dp[t]一样时,尽量选择更小的a[x]。
在1,3,5,2,8,4,6
这个例子中,当到6时,一共可以有四种不同长度,且保证该升序序列在同长度升序序列中末尾最小的升序序列。
(1)1,(2)1,3,(4)1,3,5,(6)
注:每个序列的末尾数字加括号。
这些序列都是有可能成为最长递增子序列的候选者。
tail[i]表示长度为i的递增序列末尾的数字(如上1,2,4,6存在tail中)。tail[]数组性质:tail[0] < tail[1] < … < tail[n] !!!
每次读入一个新元素时,可按照以下规则更新这些序列:
1)nums[i]比所有递增序列的末尾都小,则长度为1的序列更新为这个更小的末尾。
如果读入数字0,则更新序列为:
(0)1,(2)1,3,(4)1,3,5,(6)
2)nums[i]比所有序列的末尾都大,则直接将nums[i]加到后面。
如果读入数字9,更新序列为:
(1)1,(2)1,3,(4)1,3,5,(6)1,3,5,6,(9)
3)在中间,则更新那个末尾数字刚好大于等于nums[i]的那个序列,nums[i]替换其末尾数字。该情况下,利用二分搜索寻找。
如果读入数字3,更新序列为:
(1)1,(2)1,3,(3)1,3,5,(6)
代码:
class Solution {public:// int lengthOfLIS(vector<int>& nums) { int n=nums.size(); if(n <= 1) return n; //tail[i]表示长度为i的递增序列末尾的数字 //tail[]数组性质:tail[0]<tail[1]<...tail[n] !!! vector<int> tail(n);//初始化为n个值为0的元素 //1.len为当前最长的递增序列长度(为方便操作将len减1,从0开始,最后再加上1) int len=0; tail[0]=nums[0]; //2.每次读入一个新元素nums[i] for(int i=1;i<n;i++) {//遍历nums[]中的数 if(nums[i] < tail[0]) {//(1)nums[i]比所有递增序列的末尾都小,则长度为1的序列更新为这个更小的末尾。 tail[0]=nums[i]; } else if(nums[i] > tail[len]) {//(2)nums[i]比所有序列的末尾都大,则直接将nums[i]加到后面 tail[++len]=nums[i]; } else {//(3)在中间,则更新那个末尾数字刚好大于等于nums[i]的那个序列,nums[i]替换其末尾数字 tail[biSearch(tail, 0, len, nums[i])]=nums[i]; } } return len+1; } int biSearch(vector<int>& tail, int low, int high, int target) {//由于tail数组是有序的,故可二分查找其中元素 while(low <= high)//不能是low<high {//当low=high时还要进行一次循环!!! //此时mid=low=high.若tail[mid]<target,则low=mid+1.而不是直接返回low!!! int mid = low + (high-low)/2; if(tail[mid] == target) return mid; else if(tail[mid] > target) { high=mid-1; } else { low=mid+1; } } return low; }};
- leetcode300---Longest Increasing Subsequence(最长递增子序列)
- 最长递增子序列 (Longest Increasing Subsequence)
- 最长递增子序列 (Longest Increasing Subsequence)
- 最长递增子序列 (Longest Increasing Subsequence)
- 最长递增子序列 (Longest Increasing Subsequence)
- Longest increasing subsequence,最长递增子序列
- 最长递增子序列 (Longest Increasing Subsequence)
- 最长递增子序列-Longest Increasing Subsequence
- 最长递增子序列 (Longest Increasing Subsequence)
- Longest Increasing Subsequence 最长递增子序列
- 最长递增子序列详解(longest increasing subsequence)
- 最长递增子序列详解(longest increasing subsequence)
- 最长递增子序列详解(longest increasing subsequence)
- longest increasing subsequence (最长递增子序列)
- [动态规划-1] 最长递增子序列-Longest Increasing Subsequence
- [动态规划] 最长递增子序列 (Longest Increasing Subsequence)
- 最长递增子序列详解(longest increasing subsequence)
- 最长递增子序列详解(longest increasing subsequence)
- JAVA enum(枚举)使用详解 + 总结
- 简单的贪心。注意用结构体排序!!
- 升级centos的Python至3.5.1
- 手机显示电量原理
- Android开源项目分类汇总
- leetcode300---Longest Increasing Subsequence(最长递增子序列)
- 向下转型与运行时类型识别
- swift自学笔记(三)(泛型、守护、属性观察、扩展、单例)
- xilinx FPGA 配置原理
- EasyPR--一个开源的中文车牌识别系统
- Ubutun纯净安装使用“搜狗拼音输入法”
- LinearLayout/RelativeLayout/FrameLayout实例,以及Activity跳转
- StrictMode 严苛模式 .
- 利用commons-io.jar包中FileUtils和IOUtils工具类操作流及文件