下面的打印语句将打印“hello world”。有人能解释一下吗?

System.out.println(randomString(-229985452) + " " + randomString(-147909649));

randomString()如下所示:

public static String randomString(int i)
{
    Random ran = new Random(i);
    StringBuilder sb = new StringBuilder();
    while (true)
    {
        int k = ran.nextInt(27);
        if (k == 0)
            break;

        sb.append((char)('`' + k));
    }

    return sb.toString();
}

当前回答

Random始终返回相同的序列。它用于重排数组和其他排列操作。

要获得不同的序列,需要在某个位置初始化序列,称为“种子”。

randomSting在“随机”序列的i位置(种子=-22985452)获得随机数。然后将ASCII码用于种子位置之后的序列中的下一个27个字符,直到该值等于0。这将返回“hello”。同样的操作也适用于“世界”。

我认为该代码不适用于任何其他单词。编程的人非常了解随机序列。

这是非常棒的极客代码!

其他回答

这里的每个人都做了很好的工作,解释了代码是如何工作的,并展示了如何构建自己的示例,但这里有一个信息理论的答案,说明了为什么我们可以合理地期望存在暴力搜索最终会找到的解决方案。

26个不同的小写字母组成了我们的字母表∑。为了允许生成不同长度的单词,我们进一步添加了终止符,以生成扩展的字母表∑':=∑⑪{⑪}。

设α是符号,X是∑′上均匀分布的随机变量。获得该符号P(X=α)及其信息内容I(α)的概率由下式给出:

P(X=α)=1/|∑'|=1/27I(α)=-log₂[P(X=α)]=-log₂(1/27)=对数₂(27)

对于一个词ω∈∑*和它的∈终止的对应词ω':=ω·∈(∑')*,我们有

I(ω):=I(ω')=|ω'|*log₂(27)=(|ω|+1)*log₂(27)

由于伪随机数生成器(PRNG)是用32位种子初始化的,因此我们可以预期长度最多为

λ=地板[32/log₂(27)] - 1 = 5

由至少一个种子产生。即使我们要搜索一个6个字符的单词,我们仍有41.06%的成功率。不太破旧。

对于7个字母,我们看到接近1.52%,但我在尝试之前没有意识到这一点:

#include <iostream>
#include <random>
 
int main()
{
    std::mt19937 rng(631647094);
    std::uniform_int_distribution<char> dist('a', 'z' + 1);
 
    char alpha;
    while ((alpha = dist(rng)) != 'z' + 1)
    {
        std::cout << alpha;
    }
}

参见输出:http://ideone.com/JRGb3l

这都是关于输入种子的。相同的种子产生相同的结果时间。即使你一次又一次地重新运行你的程序,它的输出也是一样的。

public static void main(String[] args) {

    randomString(-229985452);
    System.out.println("------------");
    randomString(-229985452);

}

private static void randomString(int i) {
    Random ran = new Random(i);
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());
    System.out.println(ran.nextInt());

}

输出

-755142161
-1073255141
-369383326
1592674620
-1524828502
------------
-755142161
-1073255141
-369383326
1592674620
-1524828502

Random始终返回相同的序列。它用于重排数组和其他排列操作。

要获得不同的序列,需要在某个位置初始化序列,称为“种子”。

randomSting在“随机”序列的i位置(种子=-22985452)获得随机数。然后将ASCII码用于种子位置之后的序列中的下一个27个字符,直到该值等于0。这将返回“hello”。同样的操作也适用于“世界”。

我认为该代码不适用于任何其他单词。编程的人非常了解随机序列。

这是非常棒的极客代码!

这是关于“种子”的。相同的种子产生相同的结果。

在Java文档中,当为Random类指定种子值时,这是一个有意的特性。

如果使用同一种子创建了两个“随机”实例对每个方法调用相同的序列,它们将生成和返回相同的数字序列。为了保证这一点属性,为类Random指定特定算法。Java实现必须使用此处显示的所有算法类Random,为了Java代码的绝对可移植性。

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html

奇怪的是,你会认为拥有可预测的“随机”数字存在隐性安全问题。