HJ24 合唱队

205 阅读2分钟

Problem: HJ24 合唱队

题目描述

描述

N 位同学站成一排,音乐老师要请最少的同学出列,使得剩下的 K 位同学排成合唱队形。

设K位同学从左到右依次编号为 1,2…,K ,他们的身高分别为T1​,T2​,…,TK​ ,若存在i(1≤i≤K) 使得T1​<T2​<......<Ti−1​<Ti​ 且 Ti​>Ti+1​>......>TK​,则称这K名同学排成了合唱队形。

通俗来说,能找到一个同学,他的两边的同学身高都依次严格降低的队形就是合唱队形。

例子:

123 124 125 123 121 是一个合唱队形

123 123 124 122不是合唱队形,因为前两名同学身高相等,不符合要求

123 122 121 122不是合唱队形,因为找不到一个同学,他的两侧同学身高递减。

你的任务是,已知所有N位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
数据范围:1n30001≤n≤3000

输入描述:

用例两行数据,第一行是同学的总数 N ,第二行是 N 位同学的身高,以空格隔开

输出描述:

最少需要几位同学出列

示例1

输入:8 186 186 150 200 160 130 197 200

输出:4

算法流程

  1. 初始化两个数组increasingdecreasing,长度都为N,并将所有元素初始化为1。
  2. 从左到右遍历数组,计算increasing[i]的值。对于每个位置i,我们需要找到在i之前的所有位置j,使得height[j] < height[i],并且increasing[j] + 1 > increasing[i],则更新increasing[i] = increasing[j] + 1
  3. 从右到左遍历数组,计算decreasing[i]的值。对于每个位置i,我们需要找到在i之后的所有位置j,使得height[j] < height[i],并且decreasing[j] + 1 > decreasing[i],则更新decreasing[i] = decreasing[j] + 1
  4. 遍历数组,找到最大的increasing[i] + decreasing[i] - 1,即为最长的合唱队形的长度。
  5. 最少需要出列的同学数目为N减去最长的合唱队形的长度。

代码

function minimumStudentsOut(heights) {
  const N = heights.length;
  const increasing = new Array(N).fill(1);
  const decreasing = new Array(N).fill(1);

  // 计算increasing数组
  for (let i = 1; i < N; i++) {
    for (let j = 0; j < i; j++) {
      if (heights[j] < heights[i] && increasing[j] + 1 > increasing[i]) {
        increasing[i] = increasing[j] + 1;
      }
    }
  }

  // 计算decreasing数组
  for (let i = N - 2; i >= 0; i--) {
    for (let j = N - 1; j > i; j--) {
      if (heights[j] < heights[i] && decreasing[j] + 1 > decreasing[i]) {
        decreasing[i] = decreasing[j] + 1;
      }
    }
  }

  let maxLength = 0;
  for (let i = 0; i < N; i++) {
    const length = increasing[i] + decreasing[i] - 1;
    if (length > maxLength) {
      maxLength = length;
    }
  }

  const minimumOut = N - maxLength;
  return minimumOut;
}

复杂度

  • 时间复杂度: O(N2)O(N^2)

  • 空间复杂度: O(N)O(N)