递归总能提高性能吗?

时间:2015-01-12 23:30:12

标签: javascript performance for-loop recursion big-o

在这里,我有两种解决方案可以找到一个是否是一个回文。第一个使用递归,第二个使用循环。我很困惑我的代码与递归会如何执行而没有递归的代码。具有递归的代码是否在O(n)时间内运行?如果是这样,怎么样?

//Solution using recursion
function isPalindrome(arr) {
    //Runs on first call only
    if (typeof arr === "string"){
        //remove whitespace
        if(arr.match(/\s/)) {
            arr = arr.replace(/\s/g, "");
        }
        //convert to array
        arr = arr.split("");
    }

    //base condition
    if(arr.length === 0 || arr.length === 1) {
        //console.log(true);
        return true;
    } else {
        if (arr[0] !== arr[arr.length - 1]) {
            //console.log(false);
            return false;
        } else {
            arr.shift(); //remove first element
            arr.pop(); //remove last element

            //recursive call
            isPalindrome(arr);
        }
    }
}

//Solution without using recursion
function palindrome(str) {
    var reverseString = [];
    //remove whitespace
    if(str.match(/\s/)) {
        str = str.replace(/\s/g, "");
    }
    //convert to array
    var arr = str.split("");

    for(var i = arr.length; i > 0; i--) {
        reverseString.push(arr.pop());
    }

    if (reverseString.join("") === str) {
        return true;
    } else {
        return false;
    }

}

console.log(palindrome("racecar"));
console.log(palindrome("si racecar is"));

2 个答案:

答案 0 :(得分:3)

回答你的标题问题:

不,递归不会提高性能。它可能总是使实现更慢(与相同的基于循环的对应物相比)

关于复杂性:

您的递归解决方案很可能是O(n^2),因为arr.shift()操作可能是线性的。

自V8实施以来:array.shift操作 是线性的。请参阅https://github.com/v8/v8/blob/master/src/array.js#L596https://github.com/v8/v8/blob/master/src/array.js#L313

替代实施:

function isPalindromeZ(s) {
    for (var i = 0, len = s.length; i < len / 2; ++i) {
        if (s[i] != s[len - i - 1]) {
            return false;
        }
    }

    return true;
}

与您的实现相比,此实现的好处在于额外内存消耗为O(1)

答案 1 :(得分:1)

不,递归本身并不能提高性能,反之亦然。递归调用会增加一些开销,因此递归解决方案通常比迭代解决方案慢一些,如果存在一个简单解决方案(如示例中所示)。

递归可用于简化嵌套在自然界中的某些任务,这些任务需要迭代地解决复杂的代码。在这种情况下,递归可以提高性能,通过消除如此多的复杂性,它远远超过它增加的小开销。

您的问题中的示例不是如何使用递归的一个很好的示例。它可用于演示递归的工作原理,但无法证明递归的使用方式。

递归版本没有O(n)复杂度,更接近O(n²)复杂度。 arr.shift()调用将移动数组中的所有项,这意味着每次迭代都有一个内部循环,它运行剩余数组的长度。

此外,递归版本中存在错误;最后一行应该是:

return isPalindrome(arr);