[Week 8] LeetCode 300. Longest Increasing Subsequence

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.

题解

作为一个刚玩动态规划的新手,这道新手题确实值得一做。

复杂度为O(n^2)的算法

我们可以将序列中的每个数字看做一个节点,当节点a在另一个节点b的前面且a<b,我们就有a->b这样一条边,示例中的序列我们可以画成如下的图:

在这里插入图片描述

可以从头遍历该序列,每个节点作为序列的最后节点时序列长度记为len(v)=max{len(ui)}+1,其中ui为边ui->v的起点,因为它是一个有向无环图,故每个节点v在计算之前,len(ui)已经在它之前计算出来了。

看看伪代码:

for each node v in sequence:
	max = 0
	for each edge e(u, v):
        if len(u) > max:
        	max = len(u)
    len(v) = max
return max{len(vi)}

复杂度为O(nlogn)的算法

与前面算法不同的地方是我们使用了这样的一个数据结构(数组):

  • l[index]为长度index+1的所有递增子串最后元素最小的一个
  • length(l)代表当前找到的最长递增子串

看到使用这样一个数组,相信大家应该能明白我大概要做些什么了?仍然以示例数据举例子。首先数组l长度为0,从头遍历这个序列,对遍历到的每个元素做如下操作:

  1. 利用二分法来判断元素在数组l中的位置,什么位置呢?举个例子,如果数组中已经有{1, 3, 5, 7},现在元素4应该放在什么位置呢,嗯没错,放在5这个地方并把5换成4对吧!
  2. 上面说的是可以替换元素的情况,如果我们发现该元素比l中所有元素都大,怎么办了?我们就发现了一个更长的子序列呀,例如{1, 3, 5, 7},我们发现了9,那么l就变成了{1, 3, 5, 7, 9}

看起来很简单对吧,下面看看这个算法的代码:

class Solution {
private:
    int biSearch(vector<int> &arr, int begin, int end, int e)
    {
      if (begin >= end)
        return end;

      int mid = (begin + end) / 2;
      if (arr[mid] == e)
        return mid;

      if (arr[mid] > e) 
        return biSearch(arr, begin, mid, e);
      else {
        if (e < arr[mid + 1])
          return mid + 1;
        return biSearch(arr, mid + 1, end, e);
      }
    }
    
public:
    int lengthOfLIS(vector<int> &nums)
    {
      if (nums.size() == 0)
        return 0;

      vector<int> l(nums.size());
      int longest_index = 0;
      l[longest_index] = nums[0];

      for (size_t i = 1; i < nums.size(); i++)
      {
        int index = biSearch(l, 0, longest_index, nums[i]);
        if (l[index] > nums[i])
          l[index] = nums[i];
        else if (l[index] == nums[i])
          continue;
        else
        {
          if (index == longest_index)
          {
            ++longest_index;
            l[longest_index] = nums[i];
          }
        }
      }

      return longest_index + 1;
    }   
};

复杂度分析

第一种算法,我们可以这么来估计复杂度,首先我们需要做的是遍历一遍整个序列,而序列中的每个元素我们需要找出max{len(ui)},而这一步的复杂度大概为n,所以总复杂度为O(n^2)

第二种算法,与第一种相同的部分是我们都需要遍历一遍整个序列,但是得益于数组l这样一个有序的数据结构,使得我们可以使用二分法来找到元素在l中位置,这一步复杂度大概为logn,所以总复杂度为O(nlogn)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值