题目信息
Description:
细心的木斤发现:某一方阵走在第一列的n个军人,从左到右是按照各自的身高升序排列的,但体重上从左到右出现了乱序,木斤分别给这n个军人按照体重设定了不同的权值(从左到右第i个人的权值设为a[i])。他想知道:从左往右最多会有多少相邻的人其权值是严格升序排列的呢?(严格升序排列:a[i+1]>a[i])
输入输出及测试案例
Input:
测试数据有多组,每组两行,输入直到文件末尾。每组输入的第一行是一个整数n,表示这一方阵走在第一列的军人数。接下来一行是n个整数,表示从左到右每个军人的权值。
Output:
对于每组输入,输出一个整数,表示满足条件的最大人数,每个结果占一行。
Sample Input:
7
5 1 1 2 3 4 1
5
1 2 6 1 2
Sample Output:
4
3
个人参考答案
解题思路
这道题可以用动态规划来解决。定义 dpi 表示以第 i 个人为结尾的最长严格升序排列的长度,则我们需要求的就是 dp 数组中的最大值。
对于每个 i,我们遍历其之前的所有人 j,如果 a j < a i ,则 j 可以加入到以i 结尾的最长严格升序排列中,此时 dpi 取 dpj +1 的最大值。最终,dp 数组中的最大值就是我们所求的答案。
代码实现
#将每组测试数据的结果保存在一个列表中
ans = []
while True:
try:
# 输入n和权值数组
n = int(input())
a = list(map(int, input().split()))
# 初始化dp和res
dp = [1] * n
res = 1
# 转移dp数组,并更新res
for i in range(1, n):
for j in range(i):
if a[j] < a[i]:
dp[i] = max(dp[i], dp[j] + 1)
res = max(res, dp[i])
# 将本组测试数据的结果加入列表
ans.append(res)
except:
break
# 输出所有测试数据的结果
for res in ans:
print(res)
与此同时,我们可以使用二分查找优化算法,代码如下:
while True:
try:
# 输入n和权值数组
n = int(input())
a = list(map(int, input().split()))
# 初始化tail和ans
tail = [a[0]]
ans = 1
# 更新tail数组,并更新ans
for i in range(1, n):
if a[i] > tail[-1]:
tail.append(a[i])
else:
# 在tail数组中查找第一个大于等于a[i]的数的位置pos,用a[i]替换tail[pos]
l, r = 0, len(tail) - 1
while l < r:
mid = (l + r) // 2
if tail[mid] >= a[i]:
r = mid
else:
l = mid + 1
tail[r] = a[i]
ans = len(tail)
# 输出结果
print(ans)
except:
break
利用二分查找的这种方法利用 tail 数组保存当前已经能够形成的最长严格升序排列。在遍历第 i 个人时,如果 ai 大于 tail 数组中的最后一个元素,则 ai 可以加入到 tail 数组末尾;否则,在 tail 数组中二分查找第一个大于等于 ai 的数的位置 pos,然后用 ai 替换掉 tail[pos]。最终,tail 数组的长度就是我们所求的答案。