牛客網上的一個華為機試題,看完之后沒思路,然后看了一個人的講解,覺得思路很好,就在這里記錄一下,題目如下:
計算最少出列多少位同學,使得剩下的同學排成合唱隊形
說明:
N位同學站成一排,音樂老師要請其中的(N-K)位同學出列,使得剩下的K位同學排成合唱隊形。
合唱隊形是指這樣的一種隊形:設K位同學從左到右依次編號為1,2…,K,他們的身高分別為T1,T2,…,TK, 則他們的身高滿足存在i(1<=i<=K)使得T1<T2<......<Ti-1<Ti>Ti+1>......>TK。
你的任務是,已知所有N位同學的身高,計算最少需要幾位同學出列,可以使得剩下的同學排成合唱隊形。
我的附加說明:剩下的人你是不准去調整他們的位置的。這也是這個題的最難點,如果允許調整,那就so easy了(最大值只能有一個,其他值最多有2個,就是個簡單的剔除過多數據的問題了。。。)
eg:
輸入:
8
186 186 150 200 160 130 197 200
輸出:
4
思路如下:
首先計算每個數在最大遞增子串中的位置
186 186 150 200 160 130 197 200 quene
1 1 1 2 2 1 3 4 遞增計數
然后計算每個數在反向最大遞減子串中的位置--->計算反向后每個數在最大遞增子串中的位置
200 197 130 160 200 150 186 186 反向quene
1 1 1 2 3 2 3 3 遞減計數
然后將每個數的遞增計數和遞減計數相加
186 186 150 200 160 130 197 200 quene
1 1 1 2 2 1 3 4 遞增計數
3 3 2 3 2 1 1 1 遞減計數
4 4 3 5 4 2 4 5 每個數在所在隊列的人數+1(自己在遞增和遞減中被重復計算)
如160這個數
在遞增隊列中有2個人數
150 160
在遞減隊列中有2個人數
160 130
那么160所在隊列中就有3個人
150 160 130
每個數的所在隊列人數表達就是這個意思
總人數 - 該數所在隊列人數 = 需要出隊的人數
#include <iostream> #include <vector> #include <algorithm> using namespace std; void calIncSub(vector<int> quene, vector<int> &Num){ for(int i=1;i<quene.size();i++) for(int j=i-1;j>=0;j--) if(quene[j]<quene[i] && Num[i]<Num[j]+1) //找到前面比當前小的,且【能獲得的最大子串計數】 Num[i]=Num[j]+1; } int main(){ int n; int h; while(cin>>n){ vector<int> quene; vector<int> incNum(n,1); //初始化為n個1 vector<int> decNum(n,1); vector<int> totalNum; for(int i=0;i<n;i++){ cin >> h; quene.push_back(h); } calIncSub(quene,incNum); //找遞增子串計數 reverse(quene.begin(),quene.end()); //翻轉,即找反向的子串計數 calIncSub(quene,decNum); reverse(decNum.begin(),decNum.end()); //反向遞增即正向遞減 int max=0; for(int i=0;i<n;i++){ totalNum.push_back(incNum[i]+decNum[i]); if(totalNum[i]>max) max=totalNum[i]; } cout << n-max+1 <<endl; } return 0; }