【问题标题】:How to fill a 2D array diagonally based on coordinates如何根据坐标对角填充二维数组
【发布时间】:2026-02-16 14:05:02
【问题描述】:

我正在构建一个类似于热图的矩形阵列界面,我希望“热”位置位于阵列的左上角,而“冷”位置位于右下角。因此,我需要一个像这样对角填充的数组:

    0    1    2    3
  |----|----|----|----|
0 | 0  | 2  | 5  | 8  |
  |----|----|----|----|
1 | 1  | 4  | 7  | 10 |
  |----|----|----|----|
2 | 3  | 6  | 9  | 11 |
  |----|----|----|----|

所以实际上,我需要一个函数 f(x,y) 使得

f(0,0) = 0
f(2,1) = 7
f(1,2) = 6
f(3,2) = 11

(或者,当然,一个类似的函数 f(n),其中 f(7) = 10,f(9) = 6,等等)。

最后,是的,我知道这个问题类似于hereherehere 提出的问题,但那里描述的解决方案只遍历而不填充矩阵。

【问题讨论】:

  • 只要遍历数组,用当前步填充当前位置,不是吗?
  • 不,一个限制是数组从左到右逐行遍历。所以这就是为什么我正在寻找一个函数来计算每个值,而不是以特定方式遍历数组。
  • 那么你想直接计算f(x,y),而不是填充一个数组?因为我认为没有理由需要从左到右填充数组。因为如果您确实像 Ozan 建议的那样填充了一个数组,那么您可以直接在数组中查询 array[x][y] 以直接找到 f(x,y)...

标签: algorithm arrays math


【解决方案1】:

如果您被限制为逐行遍历数组,这是一个有趣的问题。 我将矩形分为三个区域。 左上三角右下三角中间的菱形

对于左上角三角形,第一列 (x=0) 中的值可以使用常见的算术级数1 + 2 + 3 + .. + n = n*(n+1)/2 进行计算。该三角形中具有相同 x+y 值的字段位于同一对角线上,并且值是来自第一列 + x 的总和。

同样的方法适用于右下三角形。但不是xy,而是使用w-xh-y,其中w 是矩形的宽度,h 是矩形的高度。该值必须从数组中的最大值w*h-1 中减去。

中间的菱形有两种情况。如果矩形的宽度大于(或等于)高度,则矩形的左下方字段是菱形中具有最低值的字段,并且可以从之前计算h-1 的总和。从那里您可以想象菱形是一个矩形,其 x 值为 x+y,y 值为 y,来自原始矩形。因此,新矩形中剩余值的计算很容易。
在另一种情况下,当高度大于宽度时,x=w-1y=0 处的字段可以使用该算术和计算,菱形可以想象为具有 x 值 x 和 y- 的矩形值y-(w-x-1)

例如,可以通过预先计算值来优化代码。我认为对于所有这些情况也有一个公式。也许我以后会考虑。

inline static int diagonalvalue(int x, int y, int w, int h) {
    if (h > x+y+1 && w > x+y+1) {
        // top/left triangle
        return ((x+y)*(x+y+1)/2) + x;
    } else if (y+x >= h && y+x >= w) {
        // bottom/right triangle
        return w*h - (((w-x-1)+(h-y-1))*((w-x-1)+(h-y-1)+1)/2) - (w-x-1) - 1;
    }

    // rhomboid in the middle
    if (w >= h) {
        return (h*(h+1)/2) + ((x+y+1)-h)*h - y - 1;
    }
    return (w*(w+1)/2) + ((x+y)-w)*w + x;
}

for (y=0; y<h; y++) {
    for (x=0; x<w; x++) {
        array[x][y] = diagonalvalue(x,y,w,h);
    }
}

当然,如果没有这样的限制,这样的事情应该会更快:

n = w*h;
x = 0;
y = 0;
for (i=0; i<n; i++) {
    array[x][y] = i;
    if (y <= 0 || x+1 >= w)  {
        y = x+y+1;
        if (y >= h) {
            x = (y-h)+1;
            y -= x;
        } else {
            x = 0;
        }
    } else {
        x++;
        y--;
    }
}

【讨论】:

  • 详尽的解释,干得好。确实,为所有情况使用一个公式会很优雅。另一种方法是通过后一种“干净”算法填充“参考数组”,然后在行/列约束算法中访问该数组的值。
【解决方案2】:

这个怎么样(有一个NxN 矩阵):

count = 1;
for( int k = 0; k < 2*N-1; ++k ) {
  int max_i = std::min(k,N-1);
  int min_i = std::max(0,k-N+1);
  for( int i = max_i, j = min_i; i >= min_i; --i, ++j ) {
    M.at(i).at(j) = count++;
  }
}

【讨论】:

    【解决方案3】:

    按照第三个示例中的步骤进行操作——这给出了索引(以便打印出切片)——并使用递增计数器设置值:

    int x[3][3];
    int n = 3;
    int pos = 1;
    for (int slice = 0; slice < 2 * n - 1; ++slice) {
        int z = slice < n ? 0 : slice - n + 1;
        for (int j = z; j <= slice - z; ++j)
            x[j][slice - j] = pos++;
    }
    

    【讨论】:

      【解决方案4】:

      在 M*N 矩阵中,当像您所说的示例中那样遍历时,值似乎增加了 n,但边界情况除外,所以

      f(0,0)=0
      f(1,0)=f(0,0)+2
      f(2,0)=f(1,0)+3
      

      ...依此类推,直到 f(N,0)。那么

      f(0,1)=1
      f(0,2)=3
      

      然后

      f(m,n)=f(m-1,n)+N, where m,n are index variables
      

      f(M,N)=f(M-1,N)+2, where M,N are the last indexes of the matrix
      

      这不是决定性的,但它应该可以为您提供一些工作。请注意,您只需要每行中前一个元素的值和几个起始值即可开始。

      【讨论】:

        【解决方案5】:

        如果你想要一个简单的函数,你可以使用递归定义。

        H = height
        
        def get_point(x,y)
          if x == 0
              if y == 0
                return 0
              else
                return get_point(y-1,0)+1
              end
          else
            return get_point(x-1,y) + H
          end
        end
        

        这利用了这样一个事实,即任何值都是 H+其左侧项目的值。如果项目已经在最左边的列,那么你找到最右上对角线的单元格,然后从那里向左移动,然后加 1。

        这是一个使用dynamic programming的好机会,并且“缓存”或记忆你已经完成的功能。


        如果您希望 f(n)“严格”完成某些事情,您可以使用以下关系:

        n = ( n % W , n / H ) [整数除法,无余数/小数]

        然后从那里开始你的工作。


        或者,如果您想要一个纯数组按行填充方法,没有递归,您可以遵循以下规则:

        1. 如果您位于该行的第一个单元格中,请“记住”第一行的单元格 (R-1)(其中 R 是您的当前行)中的项目,并将其加 1。
        2. 否则,只需将 H 添加到您上次计算的单元格(即左侧的单元格)。

        伪代码:(假设数组由arr[row,column]索引)

        arr[0,0] = 0
        
        for R from 0 to H
        
          if R > 0
            arr[R,0] = arr[0,R-1] + 1 
          end
        
          for C from 1 to W
        
            arr[R,C] = arr[R,C-1]
        
          end
        
        end
        

        【讨论】: