笔试题9 – 合唱队形(最长上升子序列模型)
题目重现
题目链接:合唱队形_牛客题霸_牛客网 (nowcoder.com)
题目描述:
N位同学站成一排,音乐老师要请其中的 (N-K) 位同学出列,使得剩下的K位同学排成合唱队形。
合唱队形是指这样的一种队形:设K位同学从左到右依次编号为 1,2…,K,他们的身高分别为 T1,T2,…,TK, 则他们的身高满足 t1<t2<…< ti >ti+1>…>tk−1>tk (1≤i≤k)
你的任务是,已知所有 n 位同学的身高,计算最少需要几位同学出列,可以使得剩下的同学排成合唱队形。
数据范围:1≤n≤1000,身高满足 130≤ti≤230
输入描述:
第一行输入一个正整数 n 表示同学的总数。
第二行有 n 个整数,用空格分隔,第 i 个整数 ti 是第 i 位同学的身高(厘米)。
输出描述:
输出仅有一个整数,即最少需要几个同学出列
解题思路
由上图我们得知,最长符合题意的子序列无非这三种情况,于是问题转化为从左向右和从右向左分别进行一次最长递增子序列模型的组合,符合题意的子序列长度是两者之和 - 1,注意这里 - 1 是因为 i 位置分别被向左和向右各计入一次,需要去掉重复记录。最后,打印符合题意的结果时,设求得的最长子序列长为 len ,那么需要打印 n - len。
解题代码
#include <iostream>
#include <vector>
using namespace std;
// 由 1 <= i <= k 得知,最长子序列可以是:/ 或 \ 或 /\
//
int main() {
int n = 0;
cin >> n;
vector<int> t(n, 0);
for (auto& e : t) {
cin >> e;
}
// 利用动态规划解决
vector<int> f(n + 1);
vector<int> g = f;
// 从前往后填f
for (int i = 1; i < n + 1; i++) {
f[i] = 1;
for (int j = 1; j < i; j++) {
if (t[j - 1] < t[i - 1]) {
f[i] = max(f[i], f[j] + 1);
}
}
}
// 从后往前填g
for (int i = n; i >= 1; i--) {
g[i] = 1;
for (int j = i + 1; j <= n; j++) {
if (t[j - 1] < t[i - 1]) {
g[i] = max(g[i], g[j] + 1);
}
}
}
int len = 0;
for (int i = 1; i <= n; i++) {
len = max(len, f[i] + g[i] - 1);
}
cout << n - len << endl;
return 0;
}
提交结果: