记录一道碰到的笔试题。
题目
给定一个int数组,求其最长的连续递增子序列,但递增过程中可以忽略m个数组元素。在最优子序列长度相同时,以子序列元素之和较小的一个为最优解*。
即实现方法
vector<int> getLongestSubAry(const vector<int>& array, int m)
思路
八成是动态规划,参考最长连续子序列。
需要存储状态:第i个元素的{最优序列,忽略元素个数}
从i向前寻找m个位置的最优解(因为最多只能忽略m个)。假设那个“之前的”元素是array[j],那如果array[i]>array[j]并且array[j]+1>=当前最优序列长度,则判断限制条件*以确定是否更新最优解。
整个方法的复杂度应该是[latex]O(n*m)[/latex],其中n为array的长度。
代码
#include <iostream>
#include <vector>
using namespace std;
struct OptmElem{
vector<int> results;
int omitCount;
int getResultCount(){
return results.size();
}
};
int getSum(const vector<int>& ary){
int sum = 0;
for(int i=0; i<ary.size(); i++)
sum += ary[i];
return sum;
}
/**
* Find the longest increasing subarray
* that allows skipping m elements
*/
vector<int> maxSubArray(const vector<int>& array, int m){
if(array.empty())
return vector<int>();
vector<OptmElem> bestResults;
OptmElem initOptm;
initOptm.results.push_back(array[0]);
initOptm.omitCount = m;
bestResults.push_back(initOptm);
unsigned long maxLen = 0;
int optiIndex = 0; //index of optimal result in bestResults
for(int i=1; i<array.size(); i++){
vector<int> currBest = {array[i]};
int omitCount = m;
for(int j=(i-m>=0)?(i-m):(0); j<i; j++){
//trace back j steps
//if omittance limit exceed, continue
if(bestResults[j].omitCount < (i-j-1)){
continue;
}
if((array[i] > array[j]) && (bestResults[j].getResultCount()+1 >= currBest.size())){
//new optimal
if(bestResults[j].getResultCount()+1 == currBest.size()){
//on-par result, array that has the smallest sum is the best
int oldSum = getSum(currBest);
int newSum = getSum(bestResults[j].results) + array[i];
if(newSum > oldSum){
continue; //omit this best
}
}
currBest = bestResults[j].results;
currBest.push_back(array[i]);
omitCount = bestResults[j].omitCount - (i-j-1);
}
}
OptmElem elem;
elem.results = currBest;
elem.omitCount = omitCount;
bestResults.push_back(elem);
if(maxLen < currBest.size()){
maxLen = currBest.size();
optiIndex = i;
} else if (maxLen == currBest.size()){
int oldBestSum = getSum(bestResults[optiIndex].results);
int currBestSum = getSum(currBest);
if(currBestSum < oldBestSum){
optiIndex = i;
}
}
}
return bestResults[optiIndex].results;
}