解题思路

这是一个求最长山峰序列的问题,可以通过动态规划来解决:

  1. 对于每个位置 ,分别求出以 为山峰的最长上升子序列长度和最长下降子序列长度
  2. 使用两个 数组:
    • 表示从左到 的最长上升子序列长度
    • 表示从 到右的最长下降子序列长度
  3. 遍历所有位置,找出最长的山峰序列
  4. 用总人数减去最长山峰序列的长度即为需要出列的人数

代码

#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是因为位置 被计算了两次)。