HJ24&103 求最长递增子序列

题目描述

HJ24 合唱队

N 位同学站成一排,音乐老师要请最少的同学出列,使得剩下的 K 位同学排成合唱队形。
设K位同学从左到右依次编号为 1,2…,K ,他们的身高分别为 T 1 , T 2 , … , T K T_1,T_2,…,T_K T1,T2,,TK,若存在 i ( 1 ≤ i ≤ K ) i(1\leq i\leq K) i(1iK)使得 T 1 < T 2 < . . . . . . < T i − 1 < T i T_1<T_2<......<T_{i-1}<T_i T1<T2<......<Ti1<Ti T i > T i + 1 > . . . . . . > T K T_i>T_{i+1}>......>T_K Ti>Ti+1>......>TK
则称这KK名同学排成了合唱队形。
通俗来说,能找到一个同学,他的两边的同学身高都依次严格降低的队形就是合唱队形。
例子:
123 124 125 123 121 是一个合唱队形
123 123 124 122不是合唱队形,因为前两名同学身高相等,不符合要求
123 122 121 122不是合唱队形,因为找不到一个同学,他的两侧同学身高递减。

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。

注意:不允许改变队列元素的先后顺序 且 不要求最高同学左右人数必须相等

数据范围: 1 ≤ n ≤ 3000 1 \le n \le 3000 1n3000

HJ103 Redraiment的走法

Redraiment是走梅花桩的高手。Redraiment可以选择任意一个起点,从前到后,但只能从低处往高处的桩子走。他希望走的步数最多,你能替Redraiment研究他最多走的步数吗?

数据范围:每组数据长度满足 1 ≤ n ≤ 200 1 \le n \le 200 1n200 , 数据大小满足 1 ≤ v a l ≤ 350 1 \le val \le 350 1val350

代码和解释

思路

这两道题本质上都是求一串数字最长递增子序列的长度。
HJ24这一题的合唱队队形要求可知,从左往右看,最高的人左边身高是递增的,右边则是递减的。因此等价于求队列里的一个位置,这个位置左边的最长递增子序列,和这个位置右边的最长递减子序列,这两个序列长度之和最大的情况。因为这时候需要最少的人出列就可以形成合唱队形。
而最长递减子序列逆序便是最长递增子序列,故只需要写出判断最长递增子序列的代码,两次逆序便可以求出一个数列的最长递减子序列。

代码实现
  1. 参数H是记录输入数列的列表,N是数列的长度。放在HJ24的情形下,H是记录同学们身高的列表,N是同学的总数。
  2. 函数bisect_left(L,a)返回a在L中的位置。若不存在,则返回插入a能使L有序的位置。
  3. 一位数组dp[i]记录H[0]~H[I]的最大递增子序列的长度,列表arr记录当前递增子序列。遍历数列H,如果当前数H[i]大于arr的最后一位,说明H[i]加入到arr末尾,不改变它的递增性。
    否则,找到H[i]在数组arr中的位置,可求dp[i]
import bisect
def f(H,N):
    dp=[1]*N
    arr=[H[0]]
    for i in range(1,N):
        if H[i]>arr[-1]:
            arr.append(H[-1])
            dp[i]=len(arr)
        else:
            pos=bisect.bisect_left(arr,H[i])
            arr[pos]=H[i]
            dp[i]=pos+1
    return dp
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值