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 };

 

posted @ 2019-08-30 23:32  琴影  阅读(787)  评论(0编辑  收藏  举报