【动态规划】最长递增子序列

悠悠 2023-10-02 14:14 47阅读 0赞

给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。

子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的子序列。

示例 1:

输入:nums = [10,9,2,5,3,7,101,18]
输出:4
解释:最长递增子序列是 [2,3,7,101],因此长度为 4 。
示例 2:

输入:nums = [0,1,0,3,2,3]
输出:4
示例 3:

输入:nums = [7,7,7,7,7,7,7]
输出:1

提示:

1 <= nums.length <= 2500
-104 <= nums[i] <= 104

进阶:

你可以设计时间复杂度为 O(n2) 的解决方案吗?
你能将算法的时间复杂度降低到 O(n log(n)) 吗?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/longest-increasing-subsequence
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。


解法

方法一:暴力dp, 定义dp[i] 表示到i位置的数字的最长递增子序列长度,dp[i] = dp[0...i-1] 里面的最大值+1
方法二: 排队法,把数组中的数字分队,数字比队头小或者等于则入队,否则新开一条队伍。

代码

  • go

    func m_max(a, b int) int {

    1. var res int
    2. if a > b {
    3. res = a
    4. } else {
    5. res = b
    6. }
    7. return res

    }
    func lengthOfLIS(nums []int) int {

    1. le := len(nums)
    2. dp := make([]int, le+1)
    3. var ans int
    4. ans = 1
    5. for i := 0; i < le; i++ {
    6. dp[i] = 1
    7. for j := 0; j < i; j++ {
    8. if nums[i] > nums[j] {
    9. dp[i] = m_max(dp[i], dp[j]+1)
    10. ans = m_max(ans, dp[i])
    11. }
    12. }
    13. }
    14. return ans

    }

  • js

    /**

    • @param {number[]} nums
    • @return {number}
      */
      var lengthOfLIS = function(nums) {

      let dp = [], ans = 1;
      let l = nums.length;
      for(let i=0; i<l; ++i ) dp[i] = 1;
      for(let i=0; i<l; ++i){

      1. for(let j=0; j<i; ++j){
      2. if( nums[j]<nums[i] ){
      3. dp[i] = Math.max( dp[i], dp[j]+1 );
      4. ans = Math.max(ans, dp[i])
      5. }
      6. }

      }
      return ans;
      };

  • c++

    class Solution {
    public:

    1. inline int m_max(int a, int b){
    2. return a>b?a:b;
    3. }
    4. int lengthOfLIS(vector<int>& nums) {
    5. int len = nums.size();
    6. // vector<int> dp; // dp[i] 表示第i位最长增长子序列
    7. // for(int i=0; i<len+5; i++) dp.push_back(1);
    8. // int ans = 1;
    9. // for(int i=1; i<len; i++){
    10. // for(int j=0; j<i; j++ ){
    11. // if(nums[j] < nums[i]){
    12. // // 如果j<i,则判断是否需要更新dp
    13. // dp[i] = m_max(dp[i], dp[j]+1);
    14. // ans = m_max(dp[i], ans);
    15. // }
    16. // }
    17. // }
    18. // return ans;
  1. /************ 上面是传统的递归,下面使用分堆法 ***********/
  2. vector<int> vec;
  3. int flag = 0; // 0 表示当前数字还没分堆
  4. for(int i=0; i<len; i++){
  5. flag = 0;
  6. for(int j=0, l=vec.size(); j<l; j++){
  7. if(vec[j] >= nums[i]){
  8. vec[j] = nums[i];
  9. flag = 1;
  10. break;
  11. }
  12. }
  13. if(flag==0){
  14. // 找不到堆就新建
  15. vec.push_back(nums[i]);
  16. }
  17. }
  18. return vec.size();
  19. }
  20. };

发表评论

表情:
评论列表 (有 0 条评论,47人围观)

还没有评论,来说两句吧...

相关阅读

    相关 动态规划递增序列

    给你一个整数数组 nums ,找到其中最长严格递增子序列的长度。 子序列是由数组派生而来的序列,删除(或不删除)数组中的元素而不改变其余元素的顺序。例如,\[3,6,2,7\

    相关 动态规划 递增序列

    方法一:最长公共子序列法 将问题转换成求递增排序的数组与原数组的最长公共子序列。 不知道如何排序?看这里: [七大排序算法总结][Link 1] 不知道什么是最长