您的位置:首页 > 其它

从一列数中筛除尽可能少的数使得从左往右看,这些数是从小到大再从大到小的。

2017-01-15 11:51 232 查看
提示:双端 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐