提示:双端 LIS 问题,用 DP 的思想可解。
#include <iostream>
using namespace std;
void printArray(int* arr, int len) {
for (int i = 0; i < len; ++i) {
cout << arr[i] << ' ';
}
cout << endl;
}
int binaryFind(int* lis, int target, int end) {
int low = 0;
int high = end;
while (low <= high) {
int mid = (low + high) / 2;
if (target > lis[mid]) {
low = mid + 1;
} else if (target < lis[mid]) {
high = mid - 1;
} else {
return mid;
}
}
return low;
}
/*B[i]是从左到右的,0~i个数之间满足递增的数字个数;
* C[i]为从右到左的,n- 1 ~ i个数之间满足递增的数字个数
* 最后结果为n - max{B[i] + C[i] - 1}
* */
int doubleEndLIS(int* arr, int len) {
int* dp1 = new int[len];
int* dp2 = new int[len];
int* lis = new int[len];
memset(dp1, 0, sizeof(int) * (len));
memset(dp2, 0, sizeof(int) * (len));
memset(lis, 0, sizeof(int) * (len));
dp1[0] = 1;
lis[0] = arr[0];
int maxlen = 1;
for (int i = 1; i < len; ++i) {
int pos = binaryFind(lis, arr[i], maxlen - 1);
lis[pos] = arr[i];
dp1[i] = pos + 1;
if (pos >= maxlen) {
maxlen++;
}
}
memset(lis, 0, sizeof(int) * len);
lis[0] = arr[len - 1];
dp2[len - 1] = 1;
maxlen = 1;
for (int i = len - 2; i >= 0; --i) {
int pos = binaryFind(lis, arr[i], maxlen - 1);
lis[pos] = arr[i];
dp2[i] = pos + 1;
if (pos >= maxlen) {
maxlen++;
}
}
// printArray(dp1, len);
// printArray(dp2, len);
int mid = 0;
int result = 0;
for (int i = 0; i < len; ++i) {
result = max(result, dp1[i] + dp2[i]);
if (result == dp1[i] + dp2[i])
mid = i;
}
result--;
//还原子序列
lis = new int[result];
memset(lis, 0, result * sizeof(int));
int curLen = dp1[mid];
for (int i = mid; i >= 0; --i) {
if (dp1[i] == curLen) {
lis[curLen - 1] = arr[i];
curLen--;
if (curLen == 0) {
break;
}
}
}
//结果集下标
int index = dp1[mid];
curLen = dp2[mid] - 1;
for (int i = mid + 1; i < len; ++i) {
if (dp2[i] == curLen) {
lis[index++] = arr[i];
curLen--;
if (curLen == 0) {
break;
}
}
}
printArray(lis, result);
result = len - result;
return result;
}