我能够找到解决该问题的可行解决方案,但我想知道如何才能重构此代码以使其更快。谢谢。
/*
Given a sequence of integers as an array, determine whether it is
possible to obtain a strictly increasing sequence by removing no more
than one element from the array.
*/
//var array2 = [0, -2, 5, 6]; // expect true
//var array2 = [1, 1, 1, 2, 3]; // expect false
var array2 = [1, 2, 5, 5, 5] // expect false
function almostIncreasingSequence(sequence) {
let passing = false;
sequence.forEach((number, idx, array) => {
let sequence2 = sequence.filter((num, id) => id !== idx);
let answer = sequence2.every((num, idx, array) => {
return idx === sequence2.length - 1 || num < sequence2[idx + 1];
});
if (answer) {
passing = true;
}
});
return passing;
}
console.log(almostIncreasingSequence(array2));
答案 0 :(得分:1)
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.
答案 1 :(得分:1)
请注意,当我们想要严格增加序列时,当a [i] <= a [i-1]时我们会有冲突。解决冲突有两种方法。一种是从数组中删除a [i],希望a [i + 1]与a [i-1]不冲突。另一个方法是删除a [i-1],希望a [i-2]与a [i]不冲突。
由于我们遇到a [i] <= a [i-1]的情况,最好删除a [i-1],以使序列中的新max元素小于或等于以前,因此,有更多机会在下一个元素上没有冲突。因此,如果我们可以在删除a [i]和a [i-1]之间选择,那么删除a [i-1]会更好。
当a [i-2]与a [i]不冲突时,我们可以删除a [i-1]。在代码中,sequence [prev-1]是这个a [i-2],因此在发生冲突的情况下,我们唯一的选择就是删除a [i]。
为避免实际删除数组中的元素,我使用了一个小技巧,即继续操作,这使我增加但prev保持不变,从而使新a [i]与a [i-2]比较现在应该按照严格的顺序将它们彼此相邻。
当我们不陷入继续时,我们执行prev = i而不是prev + = 1,因为我们进入继续后实际上需要在prev上加2,并且a [i]之间没有冲突和a [i-2]。如果我们在prev上只加1,我们将有prev指向a [i-1],但是我们不能将其作为从序列中“删除”的元素。
function isAlmostIncreasingSequence(sequence) {
var prev = 0;
var removed = false;
for (var i = 1; i < sequence.length; i++) {
if (sequence[i] <= sequence[prev]) {
if (removed == false) {
removed = true;
if (prev > 0 && sequence[i] <= sequence[prev - 1]) { // need to remove sequence[i] instead of sequence[prev]
continue;
}
} else {
return false;
}
}
prev = i;
}
return true;
}
var tests = [[0, -2, 5, 6], [1, 1, 1, 2, 3], [1, 2, 5, 5, 5], [1, 3, 2], [0, -2, 5, 6], [1, 2, 3, 4, 5, 3, 5, 6], [1, 1], [1, 2, 5, 3, 5], [1, 2, 3, 4, 3, 6]];
tests.forEach(function(arr){
console.log(arr.join(","), isAlmostIncreasingSequence(arr));
});