简体   繁体   English

Javascript 字符串中的加扰字符,是否所有可能的排列都一样?

[英]Scrambling characters in Javascript string, are all possible permutations equally likely?

I am currently working on a simple function that will scramble an inputted string where all possible permutations are equally likely .我目前正在研究一个简单的函数,该函数将打乱输入的字符串,其中所有可能的排列都具有相同的可能性 My code is below.我的代码如下。

function scramble(s) {
    result = s.split("");
    for(var i = 0; i < s.length; i++) {
        var j = Math.floor(Math.random() * (i + 1));
        var scrambler = result[i];
        result[i] = result[j];
        result[j] = scrambler;
    }
    return result.join("");
}

So far, the code seems to be working fine... But will all possible permutations be equally likely?到目前为止,代码似乎运行良好……但是所有可能的排列是否都一样? (I believe in Math.random and Math.floor, but I'm getting weird outputs when I look at i and j during runtime.) (我相信 Math.random 和 Math.floor,但是当我在运行时查看 i 和 j 时,我得到了奇怪的输出。)

Unless I have a horrible mistake here (please check that it makes sense), I believe this code will not create uniformly distributed permutations.除非我在这里有一个可怕的错误(请检查它是否有意义),否则我相信这段代码不会创建均匀分布的排列。

Check for eg the chance that the first char will stay in place - when i is 0, it can't be replaced with anyone, when i is 1, elements 0 and 1 would have 50% chance of swapping, and so on.检查例如第一个字符保持原位的可能性 - 当 i 为 0 时,它不能被任何人替换,当 i 为 1 时,元素 0 和 1 将有 50% 的机会交换,依此类推。 So in total, result[0] will remain in its place at probability 1/2 * 2/3 * 3/4 ... n-1/n = 1/n所以总的来说, result[0] 将以1/2 * 2/3 * 3/4 ... n-1/n = 1/n概率留在它的位置

However, the last elements' probability to stay in place is simply (n-1)/n, since you only have one chance to swap it and you choose from the entire array.但是,最后一个元素留在原地的概率只是 (n-1)/n,因为您只有一次机会交换它并且您可以从整个数组中进行选择。

You might have a better distribution if you replace the (i+1) with s.length , but the best bet is to take something known to work.如果将(i+1)替换为s.length ,则可能会获得更好的分布,但最好的办法是采用已知有效的方法。 You can start here - http://en.wikipedia.org/wiki/Random_permutation你可以从这里开始 - http://en.wikipedia.org/wiki/Random_permutation

Deep necro-posting because I had a similar question and this is the first result when searching. Deep necro-posting 因为我有一个类似的问题,这是搜索时的第一个结果。 My gut reaction was the same as other replies, but after looking at it more closely OPs solution appears to be a valid variation of Fisher-Yates.我的直觉反应与其他回复相同,但在更仔细地查看后, OPs 解决方案似乎是 Fisher-Yates 的有效变体。

Let's walk through an example using OPs implementation.让我们来看一个使用 OP 实现的示例。

Suppose that S = [1,2,3,4].假设 S = [1,2,3,4]。

First iteration: i === 0, j must equal 0. No swaps are done.第一次迭代:i === 0,j 必须等于 0。不进行任何交换。 You can skip this loop.你可以跳过这个循环。

Second iteration: i === 1, j can be either 0 or 1.第二次迭代:i === 1,j 可以是 0 或 1。

[1,2,3,4] (j === 1, no swap so same as original),
[2,1,3,4] (j === 0, swap),

Notice that [0-1] result in equal probability of all variations of 0,1请注意,[0-1] 导致 0,1 的所有变化的概率相等

Third iteration: i === 2, j can either equal 0,1,2.第三次迭代:i === 2,j 可以等于 0,1,2。

[1,2,3,4], [2,1,3,4] (j === 2, no swap so same as previous results),
[1,3,2,4], [2,3,1,4] (j === 1, swaps),
[3,2,1,4], [3,1,2,4] (j === 0, swaps),

Notice that [0-2] result in equal probability of all variations of 0,1,2请注意,[0-2] 导致 0,1,2 的所有变化的概率相等

Fourth iteration: i === 3, j can either equal 0,1,2,3.第四次迭代:i === 3,j 可以等于 0、1、2、3。

[1,2,3,4], [2,1,3,4], [1,3,2,4], [2,3,1,4], [3,2,1,4], [3,1,2,4] (j === 3, no swap so same as previous results),
[1,2,4,3], [2,1,4,3], [1,3,4,2], [2,3,4,1], [3,2,4,1], [3,1,4,2] (j === 2, swaps),
[1,4,3,2], [2,4,3,1], [1,4,2,3], [2,4,1,3], [3,4,1,2], [3,4,2,1] (j === 1, swaps),
[4,2,3,1], [4,1,3,2], [4,3,2,1], [4,3,1,2], [4,2,1,3], [4,1,2,3] (j === 0, swaps),

Notice here again that the result is all permutations of the string in equal probability!再次注意,结果是字符串的所有排列等概率!

Comparison to Fisher Yates shuffleFisher Yates shuffle 的比较

The reason this works follows very similar reasoning to "the modern algorithm" described in the linked wiki这样做的原因与链接维基中描述的“现代算法”非常相似

for i from n−1 down to 1 do
     j ← random integer such that 0 ≤ j ≤ i
     exchange a[j] and a[i]

Op is performing the same operations on each element (j is set to between 0 and i), and looping in the opposite direction. Op 对每个元素执行相同的操作(j 设置在 0 和 i 之间),并以相反的方向循环。 Whether the swapping of each element is done first or last doesn't change the outcome.每个元素的交换是先完成还是最后完成都不会改变结果。

Both OPs implementation and Fisher Yates share the reasoning pitfall that @leeor has posted. OP 实现和 Fisher Yates 都分享了@leeor 发布的推理陷阱。 Even though there is the diminishing probability of an element being swapped, each element has an equal probability of being swapped into each position giving us the desired result.即使元素被交换的概率越来越小,但每个元素被交换到每个位置的概率是相等的,从而得到我们想要的结果。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM