标签:arr 遍历 元素 牛客 长度 序列 机试 HJ24 dp
1. 题目描述
2. Solution
1、思路分析
此题是最长递增子序列的变体,基本思路是对原序列从左到右和从右到左分别求出到每个元素的最长递增子序列的长度。例如,原序列为长度为n的序列[8,20,12,15,10,9],从左至右的到序列里每个元素的最长递增子序列为l1=[1,2,2,3,2,2],从右至左为l2=[1,4,3,3,2,1],l1+l2=[2,6,5,6,4,3]。那么合唱队最长队伍是L = max(l1+l2)-1,减1是因为计算l1和l2时重复计算了一次元素本身。因此最少出列人数为原序列长度N-L。
此题关键在于求出l1,l2。可由动态规划求出。用dp[i]表示从左至右到原序列第i个元素的最长递增子序列的长度,从第i个元素往回遍历更新dp[i]的值。由于每个元素都需要往回遍历一次,时间复杂度是o(n^2)。往回遍历如何更新dp[i]的值在其他题解已有很好的介绍,这里主要写用二分法代替往回遍历的过程,时间复杂度是o(nlogn)。
二分法的过程为:首先创建数组arr=[ele_1],ele_1是原序列第一个元素,然后从第二个元素开始从左至右遍历原序列
1、如果ele_i > max(arr),将ele_i加到arr最后;
2、如果ele_i <= max(arr),用二分法找到arr中第一个比ele_i大(或相等)的元素并用ele_i替换。
2、代码实现
import bisect #引入二分法
def inc_max(l): #定义一个函数,寻找最长的子序列
arr = [l[0]] #定义列表,将传入函数的列表第一个元素放入当前元素
dp = [1]*len(l) #定义一个列表,默认子序列有当前元素1,长度是传入函数的列表长度
for i in range(1,len(l)): #从第二个元素开始查找
if l[i] > arr[-1]: #如果元素大于arr列表的最后一个元素,就把它插入列表末尾
arr.append(l[i])
dp[i] = len(arr)# 获取这个元素子序列的长度
else: # 否则,利用二分法找到比元素大的元素的位置,用新的元素替代比它大的那个元素的值,这样就能制造出一个顺序排列的子序列
pos = bisect.bisect_left(arr, l[i])
arr[pos] = l[i]
dp[i] =pos+1 # 获取这个元素子序列的长度
return dp
while True:
try:
n = int(input())
s = list(map(int,input().split()))
left_s = inc_max(s) #向左遍历查找子序列
right_s = inc_max(s[::-1])[::-1] #向右遍历查找子序列
res = [left_s[i]+right_s[i]-1 for i in range(len(s))] #因为左右都包含原元素,所以需要减1 ;得到各元素能得到的子序列的最大长度
print(n-max(res)) # 源列表长度-可以生成的最长子序列长度 得到需要剔除的最小人数
except:
break
标签:arr,遍历,元素,牛客,长度,序列,机试,HJ24,dp 来源: https://www.cnblogs.com/junstat/p/16163638.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。