使用尽可能少的 space 连续分配点数

Distribute points in a row using as little space as possible

我有一行最多可以包含 N 个点。我想在该行内从中心向外分配 x 点,使用尽可能少的 space.

我设法在行内均匀分配点,但它使用了所有可用的点 space。使用公式 floor((i+0.5)*N/x),我得到以下结果,考虑 N=9:

4 
2 6 
1 4 7 
1 3 5 7 
0 2 4 6 8 
0 2 3 5 6 8 
0 1 3 4 5 7 8 
0 1 2 3 5 6 7 8 
0 1 2 3 4 5 6 7 8

以下是上面输出中显示的索引的示例图形表示:

我想基本上限制点从中心向外太远,所以我得到的结果更像:

4 
3 5 
3 4 5 
2 3 5 6 
2 3 4 5 6 
1 2 3 5 6 7 
1 2 3 4 5 6 7 
0 1 2 3 5 6 7 8 
0 1 2 3 4 5 6 7 8

以下是上面输出中显示的索引的示例图形表示:

我正在使用 Java,这是我当前的代码

int rowLength = 9;

for (int points = 0; points <= rowLength; points++) {
    for (float i = 0; i < points; i++) {
        double result = Math.floor((i + 0.5) * rowLength / points);

        System.out.print((int) result + " ");
    }

    System.out.println();
}

如何才能最好地实现第二张图片中显示的结果,以便我的代码输出与第二个示例输出相匹配?

好吧,我们看图吧。对我来说,似乎有几行有一些共同点:

观察:

  • 蓝色线中间点填充,橙色线中间空。
  • 蓝色的是奇数,橙色的是偶数。
  • 左边的space是
    • 在奇数情况下:(rowLength - points)/2,例如(9-1)/2 = 4
    • 在偶数情况下:(rowLength -points -1)/2,例如(9-2-1)/2 = 3

让我们将其写入代码。我这里用的是C#,不过Java应该很像:

int rowLength = 9;
for (int points = 0; points <= rowLength; points++) {
    bool isOdd = points%2 == 1;
    if (isOdd)
    {
        int spaceOnSide = (rowLength-points)/2;
        for (int i=0; i<points;i++)
        {
            Console.Write(""+(i+spaceOnSide)+" ");
        }
    }
    else // even
    {
        int spaceOnSide = (rowLength-1-points)/2;
        for (int i=0; i<points/2;i++)
        {
            Console.Write(""+(i+spaceOnSide)+" ");
        }

        for (int i=points/2; i<points;i++)
        {
            Console.Write(""+(i+spaceOnSide+1)+" ");
        }           
    }
    Console.WriteLine();
}

正如观察告诉我们的那样,这非常简单。

鉴于该代码,我们可以使用一些技巧:

  1. 由于整数除法,行

    int spaceOnSide = (rowLength-1-points)/2;
    

    给出与

    相同的结果
    int spaceOnSide = (rowLength-points)/2;
    

    (没有-1).

  2. 我们可以将奇数情况下的for循环分成两部分:

    for (int i=0; i<points/2;i++)
    {
        Console.Write(""+(i+spaceOnSide)+" ");
    }
    for (int i=points/2; i<points;i++)
    {
        Console.Write(""+(i+spaceOnSide)+" ");
    }       
    

    乍一看这听起来适得其反,但请看第 3 步。

  3. 完成更改后,奇数部分和偶数部分看起来非常相似。这真的是重复的代码。唯一的区别在于 +1 部分。我们可以在那里添加 if 语句作为三元运算符:

    for (int i=0; i

  4. 如果你不喜欢三元运算符,你可以去掉它:

    (isOdd?0:1)
    

    等于

    (points+1)%2
    

最后你的代码就这么简单

int rowLength = 9;
for (int points = 0; points <= rowLength; points++) {
    int spaceOnSide = (rowLength-points)/2;
    for (int i=0; i<points/2;i++)
    {
        Console.Write(""+(i+spaceOnSide)+" ");
    }
    for (int i=points/2; i<points;i++)
    {
        Console.Write(""+(i+spaceOnSide+(points+1)%2)+" ");
    }                   
    Console.WriteLine();
}