给定一个长度为N的数组a0,a1,a2...,an-1,找出一个最长的单调递增子序列(注:递增的意思是对于任意的i<j,都满足ai<aj,此外子序列的意思是不要求连续,顺序不乱即可)。例如:给定一个长度为6的数组A{5, 6, 7, 1, 2, 8},则其最长的单调递增子序列为{5,6,7,8},长度为4。
提示:一种解法是转换为最长公共子序列问题,另外一种解法则是动态规划。当我们考虑动态规划解决时,可以定义dp[i]为以ai为末尾的最长递增子序列的长度,故以ai结尾的递增子序列
- 要么是只包含ai的子序列
- 要么是在满足j<i并且aj<ai的以ai为结尾的递增子序列末尾,追加上ai后得到的子序列
如此,便可建立递推关系,在O(N^2)时间内解决这个问题。
int binFind(int* arr, int len, int goal) {
int low = 0;
int high = len - 1;
while (low <= high) {
int mid = (low + high) >> 1;
if (arr[mid] == goal) {
return mid;
} else if (arr[mid] < goal) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return low;
}
stack<int> findLongestSubquence(int* arr, int len) {
stack<int> result;
if (!arr || !len) {
return result;
}
int* dp = new int[len];
memset(dp, 0, len * sizeof(int));
int* tmp = new int[len];
memset(tmp, 0, sizeof(int) * len);
dp[0] = 1;
tmp[0] = arr[0];
int curLen = 1;
for (int i = 1; i < len; ++i) {
int index = binFind(tmp, curLen, arr[i]);
if (index == curLen) {
curLen++;
}
tmp[index] = arr[i];
dp[i] = index + 1;
}
for (int i = len; i >= 0; --i) {
if (dp[i] == curLen) {
result.push(arr[i]);
curLen--;
if (!curLen) {
break;
}
}
}
delete dp;
delete tmp;
return result;
}