Longest Increasing Sequence

  1 public class Longest_Increasing_Subsequence {
  2     /**
  3      * O(N^2)
  4      * DP
  5      * 思路:
  6      *  示例:[1,0,2,4,10,5]
  7      *  找出以上数组的LIS的长度
  8      * 分析:
  9      *  只要求长度,并不要求找出具体的序列
 10      * 问题可以拆分为
 11      *      1. 对于[1],找出LIS
 12      *      2. 对于[1,0],找出LIS
 13      *      3. 对于[1,0,2],找出LIS
 14      *      4. 对于[1,0,2,4],找出LIS
 15      *      ...
 16      *      最后,对于[1,0,2,4,10,5],找出LIS
 17      * 再进一步思考,例如:
 18      *  找出[-1,0,1,0,2,4]的LIS,就要找到在4之前符合条件(都比4小且都为升序)的LIS的长度 => [-1,0,1]是满足情况的(最长,都是升序,都比4小)
 19      *  那么就要有一个数据结构来记录到某一个index上,LIS的长度。因为每一个index上的LIS长度并不是固定为前一个加1,所以每一个都要记录下来 => 数组dp[]
 20      *  dp[i]记录的是,在i这个index上,LIS的长度
 21      *  比如:
 22      * index 0 1 2 3 4 5
 23      *  dp:[ 1,2,3,1,4,5] //dp数组
 24      *  ar:[-1,0,1,0,2,4] //原数组
 25      *  dp[1] = 2表示在1这个index上,LIS的长度是2([-1,0])
 26      *  dp[4] = 4表示在4这个index上,LIS的长度是4([-1,0,1,2])
 27      * ----------------------------
 28      * 状态转换方程:
 29      * dp[i] = dp[k] + 1; (dp[k] = max(dp[0], dp[1], ... dp[i-1]))  // dp[i] = 在i以前最大的LIS长度加上1
 30      * 以上方程的成立条件:
 31      *      nums[k] < nums[i] //保持递增序列的属性
 32      */
 33 
 34     /**
 35      * O(N^2)
 36      */
 37     public int lengthOfLIS(int[] nums) {
 38         int[] dp = new int[nums.length];
 39         dp[0] = 1;
 40         for (int i = 1; i < nums.length; i++) {
 41             int beforeMaxLen = dp[i];
 42             // 在0 ~ i之间比较LIS的长度
 43             for(int j = 0; j < i; j++) {
 44                 if (nums[j] < nums[i] && dp[j] > beforeMaxLen) { //注意dp[j] > beforeMaxLen,新的长度要大于之前选出来的长度才能更新
 45                     beforeMaxLen = dp[j];
 46                 }
 47             }
 48             dp[i] = beforeMaxLen + 1;
 49         }
 50         int max = 0;
 51         // 在数组里找出最大的长度即可
 52         for (int i = 0; i < nums.length; i++) {
 53             if (dp[i] > max){
 54                 max = dp[i];
 55             }
 56         }
 57         return max;
 58     }
 59 
 60     /**
 61      * O(N*logN)
 62      * 思路:
 63      *  满足递增序列,就直接加入list中
 64      *  如果发现有降序出现,找出在原数组中比它大的第一个数的index,然后在list中替换那个数
 65      *  最后返回list的长度
 66      * 原理:
 67      *  因为只求长度,所以没有必要存储确切的sequence
 68      */
 69     public int lengthOfLIS_2(int[] nums) {
 70         List<Integer> list = new ArrayList<>();
 71         for(int num : nums) {
 72             if(list.isEmpty() || list.get(list.size() - 1) < num) { // 不满足递增序列
 73                 list.add(num);
 74             } else {
 75                 list.set(findFirstLargeEqual(list, num), num);
 76             }
 77         }
 78 
 79         return list.size();
 80     }
 81 
 82     private int findFirstLargeEqual(List<Integer> list, int target)
 83     {
 84         int start = 0;
 85         int end = list.size() - 1;
 86         while(start < end) {
 87             int mid = start + (end - start) / 2;
 88             if(list.get(mid) < target) {
 89                 start = mid + 1;
 90             }
 91             else {
 92                 end = mid;
 93             }
 94         }
 95 
 96         return end;
 97     }
 98 
 99     /**
100      * 测试用
101      */
102     public static void main(String[] args) {
103         Longest_Increasing_Subsequence lis = new Longest_Increasing_Subsequence();
104         int[] a = {-1,0,1,0,2,4};
105         System.out.print(lis.lengthOfLIS_2(a));
106     }
107 }

 

转载于:https://www.cnblogs.com/marshallguo/p/5579334.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值