JavaScript 排列

JavaScript Permutations

我正在计算不包含连续字母的排列数。我的代码通过了 'aabb'(答案:8)和 'aab'(答案:2)之类的测试,但没有通过 'abcdefa'(我的答案:2520;正确答案:3600)之类的测试。这是我的代码:

function permAlone(str) {

    var totalPerm = 1;
    var result = [];

    //assign the first letter
    for (var i = 0; i < str.length; i++) {
        var firstNum = str[i];
        var perm = firstNum;

        //create an array from the remaining letters in the string
        for (var k = 0; k < str.length; k++) {
            if (k !== i) {
                perm += str[k];
            }
        }

        //Permutations: get the last letter and change its position by -1;
        //Keep changing that letters's position by -1 until its index is 1;
        //Then, take the last letter again and do the same thing;
        //Keep doing the same thing until the total num of permutations of the number of items in the string -1 is reached (factorial of the number of items in the string -1 because we already established what the very first letter must be).

        var permArr = perm.split("");
        var j = permArr.length - 1;
        var patternsLeft = totalNumPatterns(perm.length - 1);

        while (patternsLeft > 0) {
            var to = j - 1;
            var subRes = permArr.move(j, to);
            console.log(subRes);

            if (noDoubleLettersPresent(subRes)) {
                result.push([subRes]);
            }

            j -= 1;
            if (j == 1) {
                j = perm.length - 1;
            }
            patternsLeft--;
        }
    }
    return result.length;
}

Array.prototype.move = function(from, to) {
    this.splice(to, 0, (this.splice(from, 1))[0]);
    return this.join("");
};

function totalNumPatterns(numOfRotatingItems) {
    var iter = 1;
    for (var q = numOfRotatingItems; q > 1; q--) {
        iter *= q;
    }
    return iter;
}

function noDoubleLettersPresent(str) {
    if (str.match(/(.)/g)) {
        return false;
    } else {
        return true;
    }
}

permAlone('abcdefa');

我认为问题出在你的排列算法上;你从哪里得到那个的?我用另一个(在 Filip Nguyen, adapted from his answer to this question 之后)尝试了它,它如预期的那样 returns 3600。

function permAlone(str) {
    var result = 0;
    var fact = [1];
    for (var i = 1; i <= str.length; i++) {
        fact[i] = i * fact[i - 1];
    }
    for (var i = 0; i < fact[str.length]; i++) {
        var perm = "";
        var temp = str;
        var code = i;
        for (var pos = str.length; pos > 0; pos--) {
            var sel = code / fact[pos - 1];
            perm += temp.charAt(sel);
            code = code % fact[pos - 1];
            temp = temp.substring(0, sel) + temp.substring(sel + 1);
        }
        console.log(perm);
        if (! perm.match(/(.)/g)) result++;
    }
    return result;
}

alert(permAlone('abcdefa'));

更新:为了回答一个相关问题,我写了一个算法,它不仅强制所有排列然后跳过具有相邻双打的排列,而且使用一种逻辑方式只生成正确的排列。在这里解释: and expanded to include any number of repeats per character here: Generate all permutations of a list without adjacent equal elements

我同意 m69,错误似乎在于您如何生成排列。通过实施不同的算法来生成排列,我得到了 'abcdefa' 3600。我的解决方案如下。由于它使用递归来生成排列,因此解决方案并不快,但是如果速度不重要,您可能会发现代码更容易理解。

使用单独的函数来生成排列中的数组索引值的原因是为了验证排列代码是否正常工作。由于输入字符串中存在重复值,因此更难调试排列算法中的问题。

// Simple helper function to compute all permutations of string indices
function permute_indices_helper(input) {
    var result = [];    
    if (input.length == 0) {
        return [[]];
    }
    for(var i = 0; i < input.length; i++) {
        var head = input.splice(i, 1)[0]; 
        var tails = permute_indices_helper(input);
        for (var j = 0; j < tails.length; j++) {
            tails[j].splice(0, 0, head);
            result.push(tails[j]);
        }
        input.splice(i, 0, head); // check
    }
    return result;
};

// Given an array length, generate all permutations of possible indices
// for array of that length.
// Example: permute_indices(2) generates:
// [[0,1,2], [0,2,1], [1,0,2], ... , [2, 0, 1]]
function permute_indices(array_length) {
    var result = [];
    for (var i = 0; i < array_length; i++) {
        result.push(i);
    }
    return permute_indices_helper(result);
}

// Rearrange letters of input string according to indices.
// Example: "car", [2, 1, 0] 
// returns: "rac"
function rearrange_string(str, indices) {
    var result = "";
    for (var i = 0; i < indices.length; i++) {
        var string_index = indices[i];
        result += str[string_index];
    }
    return result;
}

function permAlone(str) {
    var result = 0;
    var permutation_indices = permute_indices(str.length);
    for (var i = 0; i < permutation_indices.length; i++) {
        var permuted_string = rearrange_string(str, permutation_indices[i]);
        if (! permuted_string.match(/(.)/g)) result++;
    }
    return result;
}

您可以在 JSFiddle 上查看工作示例。