leetcode 300 最长上升子序列

题目描述

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

题目来源:https://leetcode-cn.com/problems/longest-increasing-subsequence

解题思路

本题目解题思路有多种,在此一一列举。

  • 基于深度搜索遍历所有的上升子序列,找到最长的子序列。
    这种方法比较简单,但是由于复杂度过高,不通过。
    // 在子序列前一个元素为 pre时,nums 从 cur 到 末尾所能找到的最长上升子序列长度。
    int lengthLTS(int pre,int cur,vector<int>& nums)
    {
        if(cur == nums.size())
            return 0;
        int take = 0;
        if(nums[cur] > pre) // 如果符合条件,才将此元素加入到上升子序列中
        {
            take = lengthLTS(nums[cur],cur + 1,nums) + 1;
        }
        int nottake = lengthLTS(pre,cur + 1,nums);
        return max(take,nottake); // 返回两者最大值
    }
      
    int lengthOfLIS(vector<int>& nums)
    {
        return lengthLTS(INT_MIN,0,nums); // 这里是假定给定数组中最小元素值大于 INT_MIN
    }
    
  • 基于动态规划求解
    本题目很容易写出状态表示——f[i] 表示以 nums[i] 元素为结尾的最长上升子序列长度。
    状态转移: f [ i ] = f [ j ] + 1 ( n u m s [ j ] &lt; n u m s [ i ] ) f[i] = f[j] + 1 (nums[j] &lt; nums[i]) f[i]=f[j]+1(nums[j]<nums[i])
    状态初始化: f [ i ] = 1 ( i ∈ { 0 , n u m s . s i z e ( ) − 1 } ) f[i] = 1 (i \in \{0,nums.size() - 1\}) f[i]=1(i{0,nums.size()1})
    int lengthOfLIS(vector<int>& nums) 
    {
        int n = nums.size();
        vector<int> f(n,1);
        for(int i = 0;i < n;i++)
          for(int j = 0;j < i;j++)
          {
              if(nums[j] < nums[i])
              {
                  f[i] = max(f[i],f[j] + 1);
              }
          }
        
        int result = 0;
        for(int i = 0;i < n;i++)
        {
            result = max(result,f[i]);
        }
        return result;
    }
    
  • 基于二分搜索求解
    这种方法的思想十分巧妙,它将该题目转换为一个可以基于二分搜索解决的题目。
    该种方法定义一个数组 q,q[i] 表示上升子序列长度为 i 时采取的最小元素值 (假定存在两个上升子序列分别为 {1,4}、{1,2},那么 q[2] = 2)。
    容易得知,q[i] 是一个单调递增的数组。
    向该数组中添加一个新的元素,有两种情况。其一,如果该元素值大于 q 数组中最后一个元素的值,表明存在一个更长的上升子序列,应该向当前数组最后添加这一元素。其二,如果该元素值小于 q 数组中最后一个元素的值,首先找到它在该数组中的位置,然后修改符合上升子序列长度为 i 时采取的最小元素值。
    int lengthOfLIS(vector<int>& nums) 
    {
      int n = nums.size();
      vector<int> q(n + 1); 
      int index = 1; // 从上升子序列长度为1的开始
      for(int i = 0;i < n;i++)
      {
          if(index == 1 || nums[i] > q[index - 1]) // 如果上升子序列长度为1,或者值大于大于当前 q中最后一个元素
          {
              q[index++] = nums[i];
              continue;
          }
          // 基于二分搜索,调整相关上升子序列的最小元素值  
          int l = 1,r = index - 1; 
          while(l < r)
          {
              int mid = l + r >> 1;
              if(q[mid] >= nums[i])
                  r = mid;
              else
                  l = mid + 1;
          }
          q[l] = nums[i];
      }
      
      return index - 1;
    }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值