转载原文地址:http://www.cnblogs.com/GodA/p/5180560.html

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

示例:

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

说明:

  • 可能会有多种最长上升子序列的组合,你只需要输出对应的长度即可。
  • 你算法的时间复杂度应该为 O(n2) 。

进阶: 你能将算法的时间复杂度降低到 O(n log n) 吗?

第一种方法:动态规划。

求 2 7 1 5 6 4 3 8 9 的最长上升子序列。我们定义d(i) (i∈[1,n])来表示前i个数以A[i]结尾的最长上升子序列长度。
  前1个数 d(1)=1 子序列为2;
  前2个数 7前面有2小于7 d(2)=d(1)+1=2 子序列为2 7
  前3个数 在1前面没有比1更小的,1自身组成长度为1的子序列 d(3)=1 子序列为1
  前4个数 5前面有2小于5 d(4)=d(1)+1=2 子序列为2 5
  前5个数 6前面有2 5小于6 d(5)=d(4)+1=3 子序列为2 5 6
  前6个数 4前面有2小于4 d(6)=d(1)+1=2 子序列为2 4
  前7个数 3前面有2小于3 d(3)=d(1)+1=2 子序列为2 3
  前8个数 8前面有2 5 6小于8 d(8)=d(5)+1=4 子序列为2 5 6 8
  前9个数 9前面有2 5 6 8小于9 d(9)=d(8)+1=5 子序列为2 5 6 8 9
  d(i)=max{d(1),d(2),……,d(i)} 我们可以看出这9个数的LIS为d(9)=5
  总结一下,d(i)就是找以A[i]结尾的,在A[i]之前的最长上升子序列+1,当A[i]之前没有比A[i]更小的数时,d(i)=1。所有的d(i)里面最大的那个就是最长上升子序列。
public int longestIncreasingSubsequence(int[] nums) {
if(nums.length==0)return 0;
int[] d=new int[nums.length];
int max=0;
for(int i=0;i<nums.length;i++){
d[i]=1; //当nums[i]之前没有比nums[i]更小的数,d[i]=1.每次重新开始计数
for(int j=0;j<i;j++){
if(nums[j]<nums[i]&&(1+d[j]>d[i]))d[i]=1+d[j];//num[j]<num[i]保证了递增的操作,因此只需要不断比较并更新d[i]
}
if(d[i]>max)max=d[i];
}
return max;
}

第二种方法:有以下序列A[]=3 1 2 6 4 5 10 7,求LIS长度。

核心思想是不断的替换,遍历nums数组,通知保证arr数组一定是一个递增的数组(因此可以使用二分法)
如果nums[i]比arr数组最右边的数字还要大,则将Nums[i]直接添加到arr数组的后边,否则nums[i]将会插入到arr[i]
中,使用二分查找法。
这里的二分查找是为了寻找第一个大于num[i]的数字。使用的是upper_bound。
如图所示

 代码如下:

class Solution {
public int lengthOfLIS(int[] nums) {
if(nums.length==0)return 0;
int max=0,next;
int[] arr=new int[nums.length];
arr[0]=nums[0];
for(int i=1;i<nums.length;i++){
next=put(arr,0,max,nums[i]); //从数组中的第二个数开始
arr[next]=nums[i];
if(max<next)max=next;
}
return max+1;
}
//找索引的方法,比如【2,1,4,5,3,6】找到nums[1]的索引为0,nums[2]=4直接添加到arr[2]中,nums[3]=5同理,nums[4]=3会把[1,4,5]中的4替换掉。
public int put(int[] a,int l,int r,int key){
if(a[r]<key)return r+1;
int mid;
while(l<=r){
if(l==r)return l;
mid=l+(r-l)/2;
//返回第一个大于key的索引
if(a[mid]<key)l=mid+1;
else r=mid;
}
return l;
}
}
 

最新文章

  1. WPF 自定义的窗口拖动
  2. sklearn学习笔记1
  3. Android笔记:C memory copy
  4. jquery循环延迟加载,用于在图片加载完成后再加载js
  5. iOS之XIB拖拽scrollView
  6. pat 1062. Talent and Virtue (25)
  7. C/C++中逗号表达式的用法
  8. POJ 3678 Katu Puzzle(2 - SAT) - from lanshui_Yang
  9. 再起航,我的学习笔记之JavaScript设计模式23(中介者模式)
  10. eclipse环境下日志打印输出
  11. cd
  12. JavaScript 异步编程的前世今生(上)
  13. Ajax跨域请求,无法传递及接收cookie信息
  14. 014 链表中倒数第k个结点
  15. 使用hadoop平台运行Apriori算法
  16. 【第一部分】07Leetcode刷题
  17. doc 常用命令
  18. MySql的基本架构演变
  19. Winform开发全套31个UI组件开源共享
  20. alarm 和 sleep

热门文章

  1. 【洛谷P1982】小朋友的数字
  2. 高考结束了,在门头沟有没有想学php建站的。
  3. mysql 修改数据类型
  4. 6.可见性关键字(volidate)
  5. 系统优化怎么做-SQL优化
  6. 三、Hadoop 的 API
  7. RMAN_PIPE
  8. SQLMAP使用详解
  9. #leetcode刷题之路13-罗马数字转整数
  10. C++ ACM基础