题目传送门:2500. 看风景
思路:
可以先将n个人的身高读进数组h[n]中,找到一个下标i,使得h[0]到h[i]的递增子序列加上h[i + 1]到h[n - 1]的递减子序列的和最长即可。
为了找到这个下标i,可以从0遍历到n - 1,以每一个下标为断点计算一次即可。
用数组i[n]存放到每个点的最长递增子序列,即i[k]表示[0,k]的最长子序列长度,这样要算i[k],可以从0到k - 1遍历,如果找到j(0 <= j <= k - 1)使得i[j] + 1 > i[k]并且h[j] < h[k],说明找到一个可以把该点加到末尾的最新长度。当然由于这里没有存放某个点之前的最长递增子序列的真正结束点的高度,而是假设就是以该点最为结束,这样可能后面某个点的身高比较低而导致最长子序列的长度比前面的还小,因此要重新遍历一次数组i,把所有小于前一位的值更新到与前一位相同。
代码:
1 #include <iostream> 2 using namespace std; 3 4 int heights[1000]; 5 6 int main(){ 7 int n; 8 cin >> n; 9 for(int i = 0; i < n; i++) 10 cin >> heights[i]; 11 //increase[i]表示[0,i]的最长递增子序列长度,decrease[i]表示[i,n - 1]的最长递减子序列长度 12 int increase[n], decrease[n]; 13 for(int i = 0; i < n; i++){ 14 increase[i] = 1; 15 for(int j = 0; j < i; ++j){ 16 if(heights[j] < heights[i] && increase[j] + 1 > increase[i]) 17 increase[i] = increase[j] + 1; 18 } 19 } 20 for(int i = 1; i < n; ++i){//保证increase数组为不减序列 21 if(increase[i] < increase[i - 1]) 22 increase[i] = increase[i - 1]; 23 } 24 for(int i = n - 1; i >= 0; i--){ 25 decrease[i] = 1; 26 for(int j = n - 1; j > i; --j){ 27 if(heights[j] < heights[i] && decrease[j] + 1 > decrease[i]) 28 decrease[i] = decrease[j] + 1; 29 } 30 } 31 for(int i = n - 2; i >= 0; --i){ 32 if(decrease[i] < decrease[i + 1]) 33 decrease[i] = decrease[i + 1]; 34 } 35 int m = max(increase[n - 1], decrease[0]); 36 for(int index = 0; index < n - 1; index++){//寻找使左右子序列长度和最大的点 37 m = max(m, increase[index] + decrease[index + 1]); 38 } 39 cout << n - m << endl; 40 return 0; 41 }