解题思路

  1. 这是一道最长上升下降子序列问题
  2. 对于每个位置i,需要求:
    • 左边的最长上升子序列长度(LIS)
    • 右边的最长下降子序列长度(LDS)
  3. 最后用总人数减去最大的(LIS + LDS - 1)即为需要出列的最少人数

代码

#include <iostream>
#include <vector>
using namespace std;

int main() {
    int n;
    while (cin >> n) {
        vector<int> heights(n);
        for (int i = 0; i < n; i++) {
            cin >> heights[i];
        }
        
        // 计算每个位置左边的最长上升子序列长度
        vector<int> left(n, 1);
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (heights[i] > heights[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 (heights[i] > heights[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);
        while (sc.hasNext()) {
            int n = sc.nextInt();
            int[] heights = new int[n];
            for (int i = 0; i < n; i++) {
                heights[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 (heights[i] > heights[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 (heights[i] > heights[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);
        }
    }
}
while True:
    try:
        n = int(input())
        heights = list(map(int, input().split()))
        
        # 计算每个位置左边的最长上升子序列长度
        left = [1] * n
        for i in range(n):
            for j in range(i):
                if heights[i] > heights[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 heights[i] > heights[j]:
                    right[i] = max(right[i], right[j] + 1)
        
        # 找出最大的合唱队形长度
        max_len = max(left[i] + right[i] - 1 for i in range(n))
        
        print(n - max_len)
    except:
        break

算法及复杂度

  • 算法:动态规划(最长上升/下降子序列)
  • 时间复杂度:,其中n为学生总数
  • 空间复杂度:,需要两个长度为n的数组存储dp值