重构Javascript以优化速度

时间:2018-09-22 22:32:47

标签: javascript optimization refactoring

我能够找到解决该问题的可行解决方案,但我想知道如何才能重构此代码以使其更快。谢谢。

/*
    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));

2 个答案:

答案 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));
});