有人可以解释我下面的代码实际上是如何工作的

时间:2015-06-19 11:25:11

标签: java

有人可以解释一下下面的代码是如何运作的。

  

问题:你有64个门,最初都是关闭的。你在门口进行了64次通行证。第一次,你访问每扇门并切换门(如果门关闭,你打开它;如果它是打开的,你关闭它)。第二次你只访问每一个第二门(#2号门,#4号,#6号......)。第三次,每隔3门(#3号门,#6号,#9号......等),直到你只访问第64门。

我发现以下代码有效,但我想知道究竟发生了什么。我不理解循环。

public class doors {
public static void main(String args[]) {
    // assume true=open, false=closed. Doors will all default to closed.
    boolean[] doors = new boolean[64];
    for (int i=0; i<64; i++) {
        for (int j=i; j<64; j=j+i+1) {
            doors[j] = !doors[j];
        }
    }
    // at the end, print out all the doors that are closed
    System.out.println("These doors are opened:");
    for (int i=0;i<64;i++){
        if (doors[i]) {
            // printing out i+1 to negate the zero-indexing
            System.out.println(i+1);
        }
    }
}
}

3 个答案:

答案 0 :(得分:2)

假设你知道for loops的工作原理,那么让我们来看看下面的例子:

首先假设所有门都关闭,关闭意味着false f ,打开意味着true t 。为了更简单的理解,我们也假设门的总数= 4

index       :     0       1       2       3
              +-----+ +-----+ +-----+ +-----+
begin       : |  f  | |  f  | |  f  | |  f  | // say all doors closed
              +-----+ +-----+ +-----+ +-----+
door number :    1       2       3       4

现在

 for (int i=0; i<4; i++) { // our example has 4 doors instead of 64
        // first iteration of outer loop, i = 0
        for (int j=i; j<4; j=j+i+1) {
            // as i = 0, j = 0 too
            // and j = j+i+1 = j + 0 + 1 = j +1 
            // so j will increment by 1
            // hence, j < 4 means the loop will rotate 4 (j = 0 to 3) times 
            doors[j] = !doors[j]; // this line do the trick, See bellow for details.
        }
    }

doors[j] = !doors[j];切换当前状态。怎么样?假设doors[j]包含false表示门已关闭,则!doors[j]将值false更改为true意味着关闭以打开!塔达,这就是我们想要的!

   index(value of j) :    0       1       2       3
                       +-----+ +-----+ +-----+ +-----+
after 1st iteration  : |  t  | |  t  | |  t  | |  t  |
                       +-----+ +-----+ +-----+ +-----+
         door number :    1       2       3       4

所有四扇门都打开了!

现在,对于外循环的第二次迭代,

 for (int i=0; i<4; i++) { // our example has 4 doors instead of 64
        // 2nd iteration of outer loop, i = 1
        for (int j=i; j<4; j=j+i+1) {
            // as i = 1, j = 1 too
            // and j = j+i+1 = j + 1 + 1 = j + 2 
            // so j will increment by 2
            // hence, j < 4 means the loop will rotate 2 (j = 1 and j = 3) times 
            doors[j] = !doors[j]; 
        }
    }

所以,

   index(value of j) :    0       1       2       3
                       +-----+ +-----+ +-----+ +-----+
after 2nd iteration  : |  t  | |  f  | |  t  | |  f  |
                       +-----+ +-----+ +-----+ +-----+
         door number :    1       2       3       4

仅关闭2门和4门门!是的,我们走在正确的轨道上!

现在您清楚地了解到,在外循环的第三次迭代中,j将以值2开头并按3递增,意味着只会切换门3

   index(value of j) :    0       1       2       3
                       +-----+ +-----+ +-----+ +-----+
after 3rd iteration  : |  t  | |  f  | |  f  | |  f  |
                       +-----+ +-----+ +-----+ +-----+
         door number :    1       2       3       4

希望这有助于您了解64门的代码如何解决问题!

最终(第4次)迭代将使所有的门,看起来像:

   index(value of j)   :    0       1       2       3
                         +-----+ +-----+ +-----+ +-----+
after final iteration  : |  t  | |  f  | |  f  | |  t  |
                         +-----+ +-----+ +-----+ +-----+
         door number   :    1       2       3       4

答案 1 :(得分:1)

第一份工作:对门1 - 64进行编号。让它们为零会使数学变得混乱。

当且仅当其数量中的因子数量为奇数时,门才会保持打开状态。

仅对于完美正方形才有效,因为任何其他数字都具有偶数个因子。 (例如,10有1,10,2和5.但25有1,25和5)。

所以保持打开的门是1,4,9,16,25,36,49和64.

所以你需要做的就是迭代完美的正方形,那就是O(N)。

你的代码解决这个问题的方式非常低效,因为它是O(N * N)。您的代码通过反复遍历门集来工作。关键表达是j=j+i+1,它绕过了越来越多的门。 doors[j] = !doors[j];改变了门的状态。

尝试使用完美平方法重新编码O(N)。这会给你的教授留下深刻的印象。

答案 2 :(得分:0)

如果你的意思是你不理解这个循环:

 for (int i=0; i<64; i++) {
    for (int j=i; j<64; j=j+i+1) {
        doors[j] = !doors[j];
    }
}

这是最直接的解决方案。在外循环中,i代表步骤(所以你总共有64个步骤),我也表示要跳过的门数(你跳多少门)来切换。因此,在循环0中,您跳过没有门切换,在循环1中,您跳过1门,在循环编号2中,每次跳过2门,...依此类推。内部循环将找到切换并存储在索引j中的实际门。因为你将在步骤编号i中跳过i门,所以你将从i开始到64并且每次将索引增加i + 1(相当于跳过i门)。希望你明白。