leetCode 300 最长递增子序列(dp,二分查找)

题目链接:点击查看

题目描述:

给定一个未排序的整数数组,求最长的递增子序列。

输入输出:

输入:nums = [10,9,2,5,3,7,101,18]

输出:4

输入:nums = [0,1,0,3,2,3]

输出:4

注意事项:按照 LeetCode 的习惯,子序列(subsequence)不必连续,子数组(subarray)或子字符串 (substring)必须连续

题目分析:

对于子序列问题,第一种动态规划方法是,定义一个 dp 数组,其中 dp[i] 表示以 i 结尾的子序列的性质。在处理好每个位置后,统计一遍各个位置的结果即可得到题目要求的结果。在本题中,dp[i] 可以表示以 i 结尾的、最长子序列长度。对于每一个位置 i,如果其之前的某个位置 j 所对应的数字小于位置 i 所对应的数字,则我们可以获得一个以 i 结尾的、长度为 dp[j]+ 1 的子序列。为了遍历所有情况,我们需要 i 和 j 进行两层循环,其时间复杂度为 O( n2)。
 
代码:
int lengthOfLIS(vector& nums) 
{
   int max_length=0,n=nums.size();
   if(n<=1)
   return n;
   vectordp(n,1);
   for(int i=0;inums[j])
		 {
		    dp[i]=max(dp[i],dp[j]+1);	
		 }	
	  }
	  max_length=max(max_length,dp[i]);	
   }
   return max_length; 
}

优化:

本题还可以使用二分查找将时间复杂度降低为 O(n log n)。我们定义一个 dp 数组,其中 dp[k] 存储长度为 k+1 的最长递增子序列的最后一个数字。我们遍历每一个位置 i,如果其对应的数字大于 dp 数组中所有数字的值,那么我们把它放在 dp 数组尾部,表示最长递增子序列长度加 1;如果我们发现这个数字在 dp 数组中比数字 a 大、比数字 b 小,则我们将 b 更新为此数字,使得之后构成递增序列的可能性增大。以这种方式维护的 dp 数组永远是递增的,因此可以用二分查找加速搜索。详见如下代码。
 
代码:
int lengthOfLIS(vector&nums)
{
	int n=nums.size();
	if(n<=1)
	return n;
	vectordp;
	dp.push_back(nums[0]);
	for(int i=1;i

 

 

你可能感兴趣的:(早年算法竞赛学过的知识点,leetcode,算法,动态规划,c++,二分查找)