最长上升子序列o(nlogn)复杂度一种简单易懂的理解

最长上升子序列有o(n^2)的复杂度这个就不说了,简单易懂,博客一大堆。我们今天来说说o(nlogn)复杂度的这个方法。

以前我学习这个算法的时候,看了很多博客,楞是看了很久才看懂,所以自己今天立志要把这个算法整的简单易懂一点儿

 

举个例子来讲解我的思路,例如我要找的序列是【 7 2 1 5 6 4 3 8 9 】

第一步 先拿出第一个数7

然后 长度为1的序列就是【7】,我表示为如下的形式

1:【7】

 

第二步加入2 ,我发现2比7小,那么我就用2代替7。这是因为如果后面出现了9 那么7,9和2,9都是一样的长的,看起来如果不换似乎也没什么问题。但是如果后面出现的不是9而是5,那么原本应该长度为2的序列2,5  就不会变成7,5(这是不合法的)。所以用2替换7是最合理的。结果就是 

1:【2】

 

第三步加入1,继续替换2 

1:【1】

 

第四步加入5,这个时候我们发现5比1大,所以我就可以扩展出长度为2的序列了,当然长度为1的序列依旧保留

1:【1】

2:【1,5】

为什么要保留长度为1的序列,是有道理的 如果这里出现的是9不是5 那么舍弃长度为1 的序列会有大麻烦。例如如果是1,9 后面要是再出现一个6,7那么最长序列应该是1,6,7如果长度为1的序列被舍弃了,那么1,9后面出现6,7就不能添加进去了。

 

第五步加入6

发现可以加入长度为1的序列扩展,长度2的序列,但是我们有了长度2的序列并且最后一位是5比6更优,所以长度为2的序列不变,但是6加入长度为2的序列可以扩展为长度3的序列

1:【1】

2:【1,5】

3:【1,5,6】

第六步加入4 ,同理4加入长度为1的序列不能改变它但是可以改变长度为2 的

1:【1】

2:【1,4】

3:【1,5,6】

 

第七加入3结果是

1:【1】

2:【1,3】

3:【1,5,6】

第八加入8结果就是长度为1的序列加入8扩展为【1,8】但是【1,3】比【1,8】优秀,所以舍弃,同理长度为2的加入2得到【1,3,8】也没有同样长度为3的序列【1,5,6】优秀,所以舍弃。但加入长度为3的序列可以得到长度4的序列【1,5,6,8】

1:【1】

2:【1,3】

3:【1,5,6】

4:【1,5,6,8】

因此我们发现了规律就是每加入一个数,找到一个长度为m的序列使得这个序列 的最后一位数比它小,长度为m+1的序列的最后一位数比它大,那么就用这位数更新长度为m+1的那个序列的最后一位数。但是如果长度m的序列是当前最长的那个序列,也就是 说意味着不存在m+1长度的序列,那么直接扩展出长度加1 的一个新序列。

最后我们加入9 发现它比最长长度的那个的最后一位还大,所以直接扩展新的序列【1,5,6,8,9】

1:【1】

2:【1,3】

3:【1,5,6】

4:【1,5,6,8】

5:【1,5,6,8,9】

 

 


#1.生成长度为N(arr的长度)的数组dp,dp[i]表示在以arr[i]结尾的情况下,arr[0…i]中的最长子序列。
#2.dp的初始值是1也是边界条件
#3.dp[i] = max(dp[j]+1,dp[i]) ,j in [0..i]
#o(n^2)

def subseq(data):
	lenghth = len(data)
	dp = [1 for i in range(lenghth)]
	for i in range(lenghth):
		for j in range(i):
			if data[j]<data[i]:
				dp[i] = max(dp[j]+1,dp[i])
	
	return max(dp)






#1.这就是我的方法,复杂度o(nlogn)
def subseq_log(data):
	def replace(dp,k):
		left = 0
		right = len(dp)-1
		while left<right:
			middle = (left+right)//2
			if k==dp[middle]:
				return 
			elif k<dp[middle]:
				right=middle
			else:
				left = middle+1
		dp[right] = k

	lenghth = len(data)
	dp = [data[0]]
	for i in range(1,lenghth):
		if data[i]>dp[-1]:
			dp.append(data[i])
		else:
			replace(dp,data[i])
	print(dp)
	return len(dp)



if __name__=='__main__':
	array = [7 ,2 ,1, 5, 6, 4, 3, 8, 9]
	print(subseq(array))
	print(subseq_log(array))

因此最长度长度是5。  一共遍历了n个数字,每个数字呢需要取寻找上面提到的那个长度为m的序列,可以用2分查找,因此复杂度是logn  因此整个算法复杂度是nlogn

 

其实仔细看看我上面的分析和别人的方法是一致的,如果把我的思路理解了再去看下面这篇文章,就可以把空间复杂度降低为o(n)而不是我现在的o(n^2)

 

 

其他的思路:https://blog.csdn.net/u013178472/article/details/54926531

  • 14
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值