Java - 沙漏

4

我只差一点点就能找到答案。我的需求是:

*******
 *****
  ***
   *
  ***
 *****
*******

我理解的内容

*******
 *****
  ***
   *
   *
  ***
 *****
*******

代码
public class HD404 {
    public static void main(String[] args) {

        int N = StdIn.readInt();
        int x = N*2-1;

        for (int i = 0; i < N; i++) {
            for (int j = i; j > 0; j--) {
                StdOut.print(" ");
            }
            for (int k = 0; k < x; k++) {
                StdOut.print("*");
            }
            x-=2;
            StdOut.println();
        }

        x = 1;
        for (int i = 0; i < N; i++) {
            for (int j = i; j < N-1; j++) {
                StdOut.print(" ");
            }
            for (int k = 0; k < x; k++) {
                StdOut.print("*");
            }
            x += 2;
            StdOut.println();
        }

    }
}

现在我只是猜测,无法确定我的错误所在。这里我漏掉了什么?


1
你试过调试器吗?看看在第一个星号打印后你的代码发生了什么。 - Nir Levy
6
点赞。这篇帖子比99%的相似帖子都要好,因为他展示出他真正努力过了。 - Hovercraft Full Of Eels
4个回答

1
问题在于你开始用1个星号(x = 1)来画沙漏的底部,而不是3个。
第二个问题是沙漏的底部只有N-2行,而不是N-1,因此循环应该从1开始而不是0。这是因为上半部分已经画了一行单个星号的线。
更正后的代码:
public static void main(String[] args) {

    int N = StdIn.readInt();
    int x = N*2-1;

    for (int i = 0; i < N; i++) {
        for (int j = i; j > 0; j--) {
            StdOut.print(" ");
        }
        for (int k = 0; k < x; k++) {
            StdOut.print("*");
        }
        x-=2;
        StdOut.println();
    }

    x = 3; // <-- not 1 here, the first line has 3 asterisks
    for (int i = 1; i < N; i++) { // <-- i starts at 1 because the first line was already drawn in the upper half
        for (int j = i; j < N-1; j++) {
            StdOut.print(" ");
        }
        for (int k = 0; k < x; k++) {
            StdOut.print("*");
        }
        x += 2;
        StdOut.println();
    }

}

作为一个旁注,您可以通过以下观察将此代码重写得更短:

  • x行需要绘制,因此我们可以循环从0x(包括对称性),并跳过中间行,以免重复绘制它
  • 对于每一行,都有x列需要绘制,它可以是空格或*
  • 对于每一行,仅当当前列位于min(i,x-i)max(i,x-i)之间时才绘制*(如果我们在上部分,则i < x-i,如果我们在下部分,则i > x-i)。

代码:

public static void main(String[] args) {
    int N = 4;
    int x = 2 * N - 1;

    for (int i = 0; i <= x; i++) {
        if (i == N) continue; // skip the middle-line for it not to be drawn twice
        for (int j = 0; j < x; j++) {
            System.out.print(j >= Math.min(i, x-i) && j < Math.max(i, x-i) ? "*" : " ");
        }
        System.out.println();
    }
}

样例输出:

*******
 ***** 
  ***  
   *   
  ***  
 ***** 
*******

1
您的代码的问题在于第二部分,您要求绘制一颗星星,但您从零开始,而应该从一开始。
解决方案
x = 1;
for (int i = 0; i < N; i++)

应该被替换为

x = 3;
for (int i = 1; i < N; i++)

0

我能想到的最简单的方法可能是防止第一个外部循环的最后一次迭代,这样你就可以防止显示第一行单星号。

我可能会这样做:

for(int i = 0; i < N && x > 1; i++)
{
    /*Code of the first inner loop*/
}

0

对于那些仍在寻找更简单、代码更少的沙漏挑战解决方案的人,这里提供了仅包含2个for循环的解决方案。

您可以将其用作参考。

public static void hourGlass(int size) {
// 2 for loops only
int dimension = (size * 2) - 1, space = 0, stars = size - 1, printed = 0;

for(int i=0; i<dimension; i++) {
    int actual = space;
    for (int j=dimension; j > 0; j--) {
        if(actual > 0) {
            System.out.print(" ");
            actual--;
        }
        else {
            System.out.print("*");
            if(stars==printed) {
                actual = space;
                printed = 0;
            } else {
                actual = 1;
                printed++;
            }
        }
    }
    if(i <= size-2) { // will pattern spaces and stars from top to middle
        space++;
        stars--;
    }
    else { // will pattern spaces and stars from middle to top
        space--;
        stars++;
    }
    System.out.println();
}

}


2
如果您想在旧问题上添加答案,请解释为什么您的答案更好/不同于其他答案。如果您不这样做,那么这会阻碍任何人向下滚动并考虑您的代码。 - Lazar Đorđević

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接