# -*- coding: utf-8 -*-
'''
Python程序员面试算法宝典---解题总结: 第5章 字符串 5.15 如何求最长递增子序列的长度
题目:
假设L=<a1, a2, ...,an>是n个不同的实数的序列,L的递增子序列是这样的一个子序列
Lin=<ak1, ak2,...,akm>,其中k1<k2<...<km且ak1<ak2<...<akm。
求最大的m值。
分析:
举例分析,假设数组为
[3, 1, 3, 8, 5, 6, 9]
实际就是选取
[3, 5, 6, 9]
还是选取
[1, 3, 5, 6, 9]的区别
典型的动态规划题目。
假设f[i]表示L[i]结尾的最长递增子序列的长度
那么有递推公式如下:
f[i+1] = { f[i] + 1, if L[i+1] > L[i]
{ f[i], if L[i+1] <= L[i]
但这样这个公式就错了,它会导致只要后一个元素只要大于前一个元素就被选中,
导致带来刚才分析的问题,即最终选取的是
[3, 5, 6, 9]
而不是
[1, 3, 5, 6, 9]
因为一个元素要么选取,要么不选取。
关键就是需要遍历所有<i中的所有下标,选择最长递增子序列
第i个元素的最长递增子序列长度是和其前面的元素相关
f[i] = {1, max f[j] + 1} , j < i and L[j] < L[i]
f[0] = 1
关键:
1 之所以没有想到
忘记动态规划中:
当前元素的状态是通过之前的元素或元素列表可以得到,
另外需要遍历当前元素之前的每个元素来确定究竟选择
当前元素前面的哪个元素来构成最长递增子序列
f[i] = max{1, max f[j] + 1}, j < i and L[j] < L[i]
参考:
Python程序员面试算法宝典
'''
def lis(array):
if not array:
return
size = len(array)
dp = [0 for i in range(size)]
# 记录结果的数组
result = [0 for i in range(size)]
dp[0] = 1
maxLen = 0
maxIndex = -1
maxResultIndex =0
# 递推
for i in range(1, size):
for j in range(0, i):
if array[j] < array[i]:
maxValue = max(1, dp[j] + 1)
if maxValue > dp[i]:
dp[i] = maxValue
maxIndex = j
else:
dp[i] = max(1, dp[i])
# 说明当前是存在递增子序列的
if maxIndex != -1:
result[maxIndex] = 1
if dp[i] > maxLen:
maxLen = dp[i]
maxResultIndex = i
# 还缺少最后一个元素.就是最长递增子序列长度最长的下标
result[maxResultIndex] = 1
return maxLen, result
def process():
array = [3, 1, 3, 8, 5, 6, 9]
maxLen, result = lis(array)
print maxLen
info = ""
for index, value in enumerate(result):
if 1 == value:
if info:
info += " " + str(array[index])
else:
info += str(array[index])
print info
if __name__ == "__main__":
process()