解题思路
这是一个求最长山峰序列的问题,可以通过动态规划来解决:
- 对于每个位置 ,分别求出以 为山峰的最长上升子序列长度和最长下降子序列长度
- 使用两个 数组:
- 表示从左到 的最长上升子序列长度
- 表示从 到右的最长下降子序列长度
- 遍历所有位置,找出最长的山峰序列
- 用总人数减去最长山峰序列的长度即为需要出列的人数
代码
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> height(n);
for(int i = 0; i < n; i++) {
cin >> height[i];
}
// 计算左边最长上升子序列
vector<int> left(n, 1);
for(int i = 0; i < n; i++) {
for(int j = 0; j < i; j++) {
if(height[i] > height[j]) {
left[i] = max(left[i], left[j] + 1);
}
}
}
// 计算右边最长下降子序列
vector<int> right(n, 1);
for(int i = n-1; i >= 0; i--) {
for(int j = n-1; j > i; j--) {
if(height[i] > height[j]) {
right[i] = max(right[i], right[j] + 1);
}
}
}
// 找出最长的山峰序列
int maxLen = 0;
for(int i = 0; i < n; i++) {
maxLen = max(maxLen, left[i] + right[i] - 1);
}
cout << n - maxLen << endl;
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[] height = new int[n];
for(int i = 0; i < n; i++) {
height[i] = sc.nextInt();
}
int[] left = new int[n];
Arrays.fill(left, 1);
for(int i = 0; i < n; i++) {
for(int j = 0; j < i; j++) {
if(height[i] > height[j]) {
left[i] = Math.max(left[i], left[j] + 1);
}
}
}
int[] right = new int[n];
Arrays.fill(right, 1);
for(int i = n-1; i >= 0; i--) {
for(int j = n-1; j > i; j--) {
if(height[i] > height[j]) {
right[i] = Math.max(right[i], right[j] + 1);
}
}
}
int maxLen = 0;
for(int i = 0; i < n; i++) {
maxLen = Math.max(maxLen, left[i] + right[i] - 1);
}
System.out.println(n - maxLen);
}
}
n = int(input())
height = list(map(int, input().split()))
# 计算左边最长上升子序列
left = [1] * n
for i in range(n):
for j in range(i):
if height[i] > height[j]:
left[i] = max(left[i], left[j] + 1)
# 计算右边最长下降子序列
right = [1] * n
for i in range(n-1, -1, -1):
for j in range(n-1, i, -1):
if height[i] > height[j]:
right[i] = max(right[i], right[j] + 1)
# 找出最长的山峰序列
max_len = 0
for i in range(n):
max_len = max(max_len, left[i] + right[i] - 1)
print(n - max_len)
算法及复杂度
- 算法:动态规划
- 时间复杂度: - 两次动态规划,每次都需要两层循环
- 空间复杂度: - 使用了两个长度为 的数组存储 值
这个题目的关键在于将合唱队形问题转化为最长上升-下降子序列问题。通过动态规划分别计算每个位置作为峰值时的最长序列长度,最后用总人数减去最长序列长度即为需要出列的人数。
代码中使用了两个 数组,分别记录从左到右的最长上升子序列和从右到左的最长下降子序列。对于每个位置 , 就是以 为峰值的最长山峰序列长度(减1是因为位置 被计算了两次)。