一.题目链接:https://leetcode.com/problems/longest-increasing-subsequence/

二.题目大意:

  给定一个没有排序的数组,要求从该数组中找到一个最长的递增子序列,并返回其长度。(递增子序列可以是不连续的)

注:子序列和子字符串或者连续子集的不同之处在于,子序列不需要是原序列上连续的值。

三.题解:

  寻找最长递增子序列问题 (LIS),是一道比较经典的问题,该问题的解法也比较多,此处我只用了两种方法实现,所以不本无也主要陈述这两种算法。

方法1:

利用动态规划解决 (最容易想到的算法),时间复杂度为O(N^2),空间复杂度为O(N),基本思想如下:

(1)定义一个数组dp,其中dp[i]表示nums数组中,以nums[i]为结尾的最长递增子序列的长度。dp数组的所有元素的初值为1。

(2)接下来对dp数组进行维护更新,从nums的首元素nums[0]开始遍历,对所有排在nums[i]元素之前的元素,如果$ dp[j]+1 > dp[i] $,则$dp[i] = dp[j] + 1$,所以状态转方程为

$$ dp[i] = \begin{cases} \max\{dp[i],dp[j]+ 1\} ,& {j < i} \\ dp[i] , & {j ≥ i} \end{cases} $$

(3)在dp数组的更新过程中,记录其最大的元素值,最终结果即该值。

代码如下:

class Solution
{
public:
int lengthOfLIS(vector<int>& nums)
{
int len = nums.size();
int rs = 0;
if(len == 0)
return 0;
vector<int>dp(len,1);//初始化dp数组
for(int i = 0; i < len; i++)
{
for(int j = 0; j < i; j++)
if(nums[i] > nums[j])
dp[i] = max(dp[i],dp[j] + 1);//更新当前位置元素的dp
rs = max(rs,dp[i]);//每次更新dp[i]时,记录最大值
}
return rs;
} };

方法2:

利用二分查找的思想,时间复杂度为O(NlogN),空间复杂度为O(N)。该算法的想如下:

(1)定义一个tail数组,其中tail[i]表示数组nums中长度为i+1的递增子序列中末尾元素最小的那个子序列的末尾元素,例如:

 len =    :      [], [], [], []   => tails[] =
len = : [, ], [, ] => tails[] =
len = : [, , ] => tails[] =

(2)很显然,tail数组一定是个递增的有序数组,tail数组的初始大小为1,初始元素我们定义为nums[0] (也可以定义为nums中其他值,但最好是nums[0],因为数组的长度可能为1),对于其更新过程,详细如下:

1.遍历数组nums中的每一元素nums[i],如果nums[i] < tail[0]的话,令tail[0] = nums[i];

2.如果 nums[i] 大于taIl数组的租后一个元素的话 (由于tail数组时递增的,相当于大于tail数组中所有的元素),此时将tail数组的size加1,并令nums[i]为tail数组中新的尾元素。

3.如果nums[i]不满足1和2中的情况的话,那就利用二分法从tail数组中找到处第一个大于nums[i]的元素的位置 (假设为K),则更新tail数组,令tail[K] = nums[i]。

最终tail数组的大小,就是最长递增子序列的长度 (根据tail数组所表示的意思可知),但是tail数组中的元素构成的序列并不一定是一个最长递增子序列,只是数组大小等于LIS的长度而已。

具体的代码如下:

class Solution
{
public:
int lengthOfLIS(vector<int>& nums)
{
int len = nums.size();
if(len == 0)
return 0;
vector<int>tail;
tail.push_back(nums[0]);//初始化tail数组,一开始长度为1
for(int i = 0; i < len; i++)
{
if(nums[i] < tail[0]) //更新tail数组首元素
tail[0] = nums[i];
else if(nums[i] > tail.back())//更新tail数组尾元素
tail.push_back(nums[i]);
else//更新tail1数组其他位置的元素,即找到第一个大于等于nums[i]的元素
{
int left = 0, right = tail.size() - 1;
while(left <= right)//利用二分法找到第一个大于等于nums[i]的元素的位置,并进行更新
{
int mid =left + (right - left) / 2;//防止溢出
if(tail[mid] >= nums[i])
right = mid - 1;
else
left = mid + 1;
}
tail[left] = nums[i]; //left即第一个大于等于nums[i]的元素的位置
}
}
return tail.size();//最终tail数组的大小即所求的结果
} };

注:此处的tail数组实质为一个动态数组,所以用vector来实现最好不过了。

利用二分法查找数组中第一个大于等于key的问题实质为二分查找的变种。

参考:https://leetcode.com/problems/longest-increasing-subsequence/discuss/74824/JavaPython-Binary-search-O(nlogn)-time-with-explanation

  

LeetCode——300. Longest Increasing Subsequence的更多相关文章

  1. [LeetCode] 300. Longest Increasing Subsequence 最长递增子序列

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

  2. leetcode@ [300] Longest Increasing Subsequence (记忆化搜索)

    https://leetcode.com/problems/longest-increasing-subsequence/ Given an unsorted array of integers, f ...

  3. Leetcode 300 Longest Increasing Subsequence

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

  4. [leetcode]300. Longest Increasing Subsequence最长递增子序列

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

  5. [leetcode] 300. Longest Increasing Subsequence (Medium)

    题意: 求最长增长的子序列的长度. 思路: 利用DP存取以i作为最大点的子序列长度. Runtime: 20 ms, faster than 35.21% of C++ online submissi ...

  6. LeetCode 300. Longest Increasing Subsequence最长上升子序列 (C++/Java)

    题目: Given an unsorted array of integers, find the length of longest increasing subsequence. Example: ...

  7. 【LeetCode】300. Longest Increasing Subsequence 解题报告(Python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...

  8. 【leetcode】300.Longest Increasing Subsequence

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

  9. 【刷题-LeetCode】300. Longest Increasing Subsequence

    Longest Increasing Subsequence Given an unsorted array of integers, find the length of longest incre ...

随机推荐

  1. C# 创建对象的方法

    1.实例化方法,也就是new(): //where T:new () 表示T必须有构造函数 public static T Create<T> where T:new () { retur ...

  2. Python3+getopt解析命令行参数

    一.说明 在学C语言的时候就知道可以通过argc获取命令行参数个数,可以通过argv获取具体参数.但自己写的程序获取到的参数一是没有键值形式二是写的参数不能乱序,和系统命令不太一样. 再往后点知道有g ...

  3. Win10系列:C#应用控件基础14

    ProgressBar控件 有时候用户需要执行比较复杂的任务,等待任务完成需要很长时间,在等待的过程中一般会使用进度条提示当前任务的执行进度,让用户更好的掌握任务的执行状态,例如在下载资源时会显示下载 ...

  4. Handlebars的基本用法

    使用Handlebars,你可以轻松创建语义化模板,Mustache模板和Handlebars是兼容的,所以你可以将Mustache导入Handlebars以使用 Handlebars 强大的功能. ...

  5. DevExpress.Mvvm.Free

    DevExpress MVVM Framework is a set of components helping to work in the Model-View-ViewModel pattern ...

  6. Linux应用调试 :使用gdb和gdbserver进行远程调试

    一.引言 在日常程序开发中不免遇到类似空指针操作导致程序崩溃的问题,所以需要一定的手段去定位bug,而断点调试是普遍使用的技巧,比如Windows中用VC++的debug模式进单步运行.断点调试等,而 ...

  7. Problem C: 类的初体验(III)

    Description 定义一个类Data,只有一个double类型的属性和如下4个方法: 1.   缺省构造函数,将属性初始化为0,并输出“Initialize a data 0”. 2.  带参构 ...

  8. python的安装和配置

    第一步,我们先来安装Python,博主选择的版本是最新的3.4.2版本.windows下面的Python安装一般是通过软件安装包安装而不是命令行,所以我们首先要在Python的官方主页上面下载最新的P ...

  9. 一个class标签里面有多个属性时的提取标签

    <div class="uibox-con carpic-list03 border-b-solid">   #即这个标签同时满足三个class:“uibox”.“ca ...

  10. 支付宝电脑支付沙箱配置(JAVA)

    支付宝电脑支付API地址:https://docs.open.alipay.com/270/105899/.支付宝提供了沙箱环境提供测试,具体配置步骤如下 1.先下载测试DEMO工程 下载地址:htt ...