If I'm understanding the problem right, you only need to make 1 pass through the sequence. You're looking for arrays where the difference between index (i-1) and (i) decreases only one time in the whole array.
(this code has gone through several edits to handle edge cases)
function almostIncreasingSequence(sequence) {
if(sequence.length == 1)
return true;
var countDecreases = 0;
var i = -1;
for(var index=1; index<sequence.length; index++)
{
if(sequence[index-1] > sequence[index])
{
countDecreases++;
i = index;
if(countDecreases > 1)
return false;
}
}
var canRemovePreviousElement = (i == 1 || sequence[i-2] <= sequence[i]);
var cannotRemoveSelectedElement = (i+1 < sequence.length && sequence[i-1] > sequence[i+1]);
if(canRemovePreviousElement)
return cannotRemoveSelectedElement;
return (countDecreases == 1 && !cannotRemoveSelectedElement);
}
// Testing /////////////////////////////////
var passTestCases = {
"remove index 0": [2, 0, 1, 2],
"remove index 1": [0, 1, 0, 0, 1],
"remove index (last-1)": [0, 1, -1, 2],
"remove index (last)": [0, 1, 2, -1],
"remove only element": [1]
};
var failTestCases = {
"remove index 0 or 1": [0, -1, 1, 2],
"remove any index, all increasing": [1, 2, 5, 5, 5],
"remove any index, with decrease": [1, 0],
"one decrease": [0, 1, 2, 0, 1],
"two decreases": [1, 0, 2, 1],
"no elements to remove": []
};
runTests(passTestCases, true, almostIncreasingSequence);
runTests(failTestCases, false, almostIncreasingSequence);
function runTests(testCases, expectedResult, method) {
console.log("\nShould Return " + expectedResult);
for(var key in testCases)
{
var testCase = testCases[key];
var result = method(testCase);
console.log(key + ": " + testCase + ": result " + result);
}
}
On optimizing for speed:
This method will only make one pass through the array, while the original post uses nested loops. In general, a linear algorithm will be faster than a non-linear algorithm for large data sets.
Comparing the speeds of the two algorithms with these tiny test cases gives inconclusive results.