牛客网合唱队
题目描述
计算最少出列多少位同学,使得剩下的同学排成合唱队形
说明:
N位同学站成一排,音乐老师要请其中的(N-K)位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为1,2…,K,他们的身高分别为T1,T2,…,TK, 则他们的身高满足存在i(1<=i<=K)使得T1<T2<…<Ti-1Ti+1>…>TK。
你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
注意不允许改变队列元素的先后顺序
请注意处理多组输入输出!
输入描述:
整数N
输出描述:
最少需要几位同学出列
示例1
输入
8
186 186 150 200 160 130 197 200
输出
4
题目分析
可以分别求出每个位置的最长上升子序列长度与最长下降子序列长度,然后每个位置的这两个值相加并减一,取最大值,这个最大值就是合唱队人数的最大值。需要出列的人数=总人数减去合唱队人数最大值。
代码示例
import bisect
def lis(items):
"""
Name: 最长上升子序列数量列表
Arg: 列表
return: 返回一个列表,每个元素代表原列表的该索引的最长上升子序列。
"""
# 维护一个tmp_l列表,该列表用来维护有序上升子序列,用于二分查找使用。
tmp_l = []
len_list = []
for height in items:
if not tmp_l:
tmp_l.append(height)
len_list.append(1)
elif height > tmp_l[-1]:
tmp_l.append(height)
len_list.append(len_list[-1] + 1)
else:
index = bisect.bisect_left(tmp_l, height)
tmp_l[index] = height
len_list.append(len_list[-1])
return len_list
while True:
try:
# 获取数量
cound = int(input())
# 获取身高列表
heights = list(map(int, input().split()))
# 获取左边的最长上升子序列数量列表
left = lis(heights)
# 获取游遍的最长下降子序列数量列表
right = lis(list(reversed(heights)))
right = list(reversed(right))
# 将对应索引的元素相加,总数减它,并加一。
print(cound - max(map(sum, zip(left, right))) + 1)
except:
break