zoukankan      html  css  js  c++  java
  • leetcode 300. Longest Increasing Subsequence

    Given an unsorted array of integers, find the length of longest increasing subsequence.

    Example:

    Input: [10,9,2,5,3,7,101,18]
    Output: 4 
    Explanation: The longest increasing subsequence is [2,3,7,101], therefore the length is 4. 

    Note:

    • 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?

    分析:求解数组最长递增子序列(严格递增).

    思路一:暴力求解。递归。

    最简单的方法是找出所有的递增子序列,然后返回最长递增子序列的长度。为此,我们使用递归函数lengthOfLIS返回当前元素(对应于curpos)以后可能出现的LIS长度(包括当前元素)。在每个函数调用中,我们考虑两种情况:

    1) 当前元素比LIS中包含的前一个元素大。在这种情况下,我们可以在LIS中包含当前元素。因此,我们通过包含它来求出LIS的长度。此外,我们还通过在LIS中不包含当前元素来确定LIS的长度。因此,当前函数调用返回的值是两个长度中的最大值。

    2) 当前元素小于LIS中包含的前一个元素。在这种情况下,我们不能在LIS中包含当前元素。因此,我们仅通过在LIS中不包含当前元素来确定LIS的长度。

     1 class Solution {
     2 public:
     3     int lengthOfLIS(vector<int>& nums) {
     4         int len = nums.size();
     5         return lengthOfLIS(nums, INT_MIN, 0, len);
     6     }
     7 private:
     8     int lengthOfLIS(vector<int> nums, int prev, int curpos, int len) {
     9         if (curpos == len) {
    10             return 0;
    11         }
    12         int taken = 0;
    13         if (nums[curpos] > prev) {
    14             taken = 1 + lengthOfLIS(nums, nums[curpos], curpos + 1, len);
    15         }
    16         int notaken = lengthOfLIS(nums, prev, curpos + 1, len);
    17         return max(taken, notaken);
    18     }
    19 };

    时间复杂度O(2n)

    思路二:记忆化的递归

    在前一种方法中,许多递归调用必须一次又一次地使用相同的参数。通过将特定调用的结果存储在二维记忆数组memo中,可以消除这种冗余。memo[i][j]表示可以使用nums[i]作为LIS中包含/不包含的前一个元素,而nums[j]作为LIS中包含/不包含的当前元素,来表示LIS的长度。这里,nums表示给定的数组。

     1 class Solution {
     2 public:
     3     int lengthOfLIS(vector<int>& nums) {
     4         
     5         int len = nums.size();
     6         vector<vector<int> > memo(len + 1, vector<int>(len, -1));
     7         //memset(memo, -1, sizeof(memo));
     8         return lengthOfLIS(nums, -1, 0, len, memo);
     9     }
    10 private:
    11     int lengthOfLIS(vector<int> nums, int previndex, int curpos, int len, vector<vector<int> > &memo) {
    12         if (curpos == len) {
    13             return 0;
    14         }
    15         if (memo[previndex + 1][curpos] >= 0) {
    16             return memo[previndex + 1][curpos];
    17         }
    18         int taken = 0;
    19         if (previndex < 0 || nums[curpos] > nums[previndex]) {
    20             taken = 1 + lengthOfLIS(nums, curpos, curpos + 1, len, memo);
    21         }
    22         int notaken = lengthOfLIS(nums, previndex, curpos + 1, len, memo);
    23         memo[previndex + 1][curpos] = max(taken, notaken);
    24         return memo[previndex + 1][curpos];
    25     }
    26 }; 

    时间复杂度O(n2), 空间复杂度 O(n2)

    思路三:动态规划,dp[i]表示以下标为i的数字为结尾的最长递增子序列长度。

     1 class Solution {
     2 public:
     3     int lengthOfLIS(vector<int>& nums) {
     4         int len = nums.size();
     5         vector<int> dp(len, 0);
     6         int maxn = 0;
     7         for (int i = 0; i < len; i++) {
     8             dp[i] = 1;
     9             for (int j = 0; j < i; j++) {
    10                 if (nums[i] > nums[j])
    11                     dp[i] = max(dp[i], dp[j] + 1);
    12             }
    13             maxn = max(maxn, dp[i]);
    14         }
    15         return maxn;
    16     }
    17 };

    时间复杂度:O(n2), 空间复杂度O(n)

    思路四:动规+二分

     1 class Solution {
     2 public:
     3     int lengthOfLIS(vector<int>& nums) {
     4         int len = nums.size();
     5         if (len == 0)
     6             return 0;
     7         int *dp = new int[len];
     8         int length = 0;
     9         for (int i = 0; i < len; i++) {
    10             int ind = BinarySearch(dp, 0, length, nums[i]);
    11             dp[ind] = nums[i];
    12             if (ind == length)
    13                 length++;
    14         }
    15         return length;
    16     }
    17 private:
    18     //返回数组中第一个大于target的数的下标
    19     int BinarySearch(int *p, int left, int right, int target) {
    20         while (left < right) {
    21             int mid =  ((right - left) >> 1) + left;
    22             if (p[mid] < target)
    23                 left = mid + 1;
    24             else
    25                 right = mid;
    26         }
    27         return right;
    28     }
    29 };
  • 相关阅读:
    牛客练习赛16
    AtCoder Regular Contest 096
    基础实验4-2.8 部落 (25分)--并查集
    进阶实验4-3.3 完全二叉搜索树 (30分)
    进阶实验4-3.2 Windows消息队列 (25分)--建堆
    基础实验4-2.5 关于堆的判断 (25分)---建小顶堆
    基础实验4-2.4 搜索树判断 (25分)--二叉搜索树
    基础实验4-2.1 树的同构 (25分)--二叉树
    案例4-1.7 文件传输 (25分)--并查集
    进阶实验3-3.1 求前缀表达式的值 (25分)--堆栈
  • 原文地址:https://www.cnblogs.com/qinduanyinghua/p/11437586.html
Copyright © 2011-2022 走看看