題目描述:ios
從一列數中篩除儘量少的數使得從左往右看,這些數是從小到大再從大到小的(網易)。spa
分析:.net
這能夠用雙端LIS方法來解決,先求一遍從左到右的,再求一遍從右到左的。最後從裏面選出和最大的便可。code
代碼實現:blog
#include <iostream> using namespace std; int DoubleEndLIS(int *arr, int len) { int *LIS = new int[len]; int *lefToRight = new int[len]; //leftToRight[i]表示0~i最長子序列長度-1 int *rightToLeft = new int[len]; int maxLen = 0; //記錄總共的(上升+降低)最長子序列長度 int low, high, mid; for (int i = 0; i < len; ++i) { lefToRight[i] = 0; LIS[i] = 0; } LIS[0] = arr[0]; for (int i = 1; i < len; i++) { low = 0; high = lefToRight[i-1]; while (low <= high) { mid = (low + high)/2; if (LIS[mid] < arr[i]) { low = mid + 1; } else { high = mid -1; } } LIS[low] = arr[i]; if (low > lefToRight[i-1]) { lefToRight[i] = lefToRight[i-1] + 1; //最長子序列長度加1 } else { lefToRight[i] = lefToRight[i-1]; } } //leftToRight的每一個值增長1,由於他們是最長子序列值-1 //此時leftToRight表示的是最長子序列的真正值。 for (int i = 0; i < len; i++) { lefToRight[i]++; } //從右到左 for (int i = 0; i < len; i++) { rightToLeft[i] = 0; LIS[i] = 0; } int k = 0; LIS[0] = arr[len-1]; for (int i = len -2; i >= 0; --i) { low = 0; high = rightToLeft[k]; while (low <= high) { mid = (low + high)/2; if (LIS[mid] < arr[i]) { low = mid + 1; } else { high = mid - 1; } } LIS[low] = arr[i]; if (low > rightToLeft[k]) { rightToLeft[k+1] = rightToLeft[k] + 1; } else { rightToLeft[k+1] = rightToLeft[k]; } ++k; } for (int i = 0; i < k; ++i) { rightToLeft[i]++; } //求最大值即爲要求的 for (int i = 0; i < len; ++i) { cout<<"i: "<<i<<" "<<lefToRight[i]<<" "<<rightToLeft[len-i-1]<<endl; if (lefToRight[i] + rightToLeft[len-i-1] > maxLen) maxLen = lefToRight[i] + rightToLeft[len-i-1]; } cout<<"maxLen:"<<maxLen<<endl; delete LIS; delete lefToRight; delete rightToLeft; return len - maxLen + 1; } int main() { int arr[] = {1,5,7,6,9,3,8,4,2}; int ret; ret = DoubleEndLIS(arr, 9); cout<<ret<<endl; return 0; }
參考:http://blog.csdn.net/nciaebupt/article/details/8466049ci
可是,他的程序有問題,我作了修改。get