先升后降
从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的,连续出现的数值不应该有相等的情况。
输入:1 2 4 7 11 10 9 15 3 5 8 6 输出:1 2 4 7 11 10 9 8 6
这道题用的是最长上升子序列(LIS)和最长下降子序列(LDS)
def LIS(a): # a是待处理的数组
n = len(a)
f = [1] * n # 初始化f
for i in range(0, n):
for j in range(0, i):
if a[j] < a[i]:
f[i] = max(f[i], f[j]+1) # 最重要的一步
return f # 返回的是处理后的序列
输入:1 2 4 7 2 11
输出:1 2 3 4 2 5
对于1,前面没有比它小的元素,f[0]=1
对于2,前面1比2小,f[1]=max(f[i], f[j]+1),则f[1]=2
对于4,前面比4小的元素1,2,则f[2]=3
对于7,同理,f[3]=4
对于2,前面2小的元素,只有1,f[4]=2
...
至此,原数组a 更新为 f
最长递减子序列,同理,唯一改变的是a[j] > a[i],此元素前面有没有比它的元素。
时间复杂度O(n2)
def LDS(a):
n = len(a)
f = [1] * n
for i in range(0, n):
for j in range(0, i):
if a[j] > a[i]:
f[i] = max(f[i], f[j]+1)
return f
更新后的f,找到了,那么怎样去原数组中,找到这样的序列呢?
百度说,这是寻找路径,想了好久,才想明白,以递增为例讲述
例如f为1 2 2 3 3 4 5 2 1
观察f,可以知道,最长递增子序列的长度是5(f中元素的最大值)
在f中,从5开始,向前遍历,找到5,对应 a中的元素,将元素放人Rlis[]中(f和a下标是一一对应的,通过f中的下标,可以找到a中的元素)
之后依次放入4,3,2,1下标对应a中的元素
5的下标,可以通过f.index(max(f))(这是寻找最值下标的方式)
python中,枚举列表时,索引仍然是从前先后的,这里用了一个标志,flag,最初flag=f.inf.index(max(f)),从后向前循环f,找到5,4,3,2,1对应a中的元素,存入数组,倒序输出。
1、flag,用于索引,下标,找到a中对应的元素
2、K,5,4,3,21,找到5对应的元素后,K-1,接着找4,与f中的元素一一对应
1,2是我认为比较重要的标记
如果,f数组是这样的1,2,2,1,3,4,5,有两个1,2,选哪一个呢?
例如,找到3后,K-1,K=2,最先遇见的2,就是一定符合要求的2,当然 面前的一个2也可能符合要求,这里我们要找一定可以符合要求的
x1 x2 x3 在数组中例如都是2
那么x3
def path(f, a):
r = [] # path 用于存储路径
K = max(f) # f 中的最大值
N = f.index(max(f)) # 找到f最大值 的下标
flag = N # 从最大下标开始,遍历f,小于最大下标的,都可以直接跳过
for i in f[N::-1]: # 从后向前遍历,index 仍然是0,1,2,3;所以用了一个flag
# print(i)
if i == K:
r.append(a[flag]) # 原数组
K = K - 1
flag = flag - 1
# print('最长子序列', r[::-1])
return r[::-1]
先升后降的代码
# 第七题 先升后降
# import random
# random.shuffle(arr)
# print('原数列:', arr)
arr = list(map(int, input().split()))
def LIS(a):
n = len(a)
f = [1] * n
for i in range(0, n):
for j in range(0, i):
if a[j] < a[i]:
f[i] = max(f[i], f[j]+1)
return f
# print('最长LIS:', max(f))
# print('计算后的',f)
def LDS(a):
n = len(a)
f = [1] * n
for i in range(0, n):
for j in range(0, i):
if a[j] > a[i]:
f[i] = max(f[i], f[j]+1)
return f
# f = LDS(arr)
# print('最长LDS:', max(f))
# print('计算后的',f)
def path(f, a):
r = [] # path 用于存储路径
K = max(f) # f 中的最大值
N = f.index(max(f)) # 找到f最大值 的下标
flag = N # 从最大下标开始,遍历f,小于最大下标的,都可以直接跳过
for i in f[N::-1]: # 从后向前遍历,index 仍然是0,1,2,3;所以用了一个flag
# print(i)
if i == K:
r.append(a[flag]) # 原数组
K = K - 1
flag = flag - 1
# print('最长子序列', r[::-1])
return r[::-1]
#
# print(path(f))
MAX = 1 # 计算先升后降
Flag = 1 # 从哪儿断开比较合适 存储索引
list1 = []
list2 = []
for index, item in enumerate(arr):
list1 = LIS(arr[:index+1])
list2 = LDS(arr[index:])
tmp = max(list1)+max(list2)-1
if tmp > MAX:
MAX = tmp
Flag = index
# 分成两个数组,分别计算
list1 = arr[:Flag+1]
list2 = arr[Flag:]
left = path(LIS(list1), list1)
right = path(LDS(list2), list2)
right.pop(0) # 去除重复的
left.extend(right) # 合并在一起
for index, item in enumerate(left):
left[index] = str(item)
print(*left)
新手入门,暴力解题,不完美
请大神轻喷