【问题标题】:2d array diagonally filling二维数组对角填充
【发布时间】:2014-11-13 08:08:28
【问题描述】:
1 2 3
4 5 6
7 8 9

这是我的普通数组,但我需要像这样对角线

1 2 4
3 5 7
6 8 9

这是使它工作的非常愚蠢的方法,但即使它不起作用,因为我无法找到第二列元素。

for (i = 0; i < arr.length; ++i) {
    for (n = 0; n < arr[0].length; ++n) {
        if (i == 0 && n == 0){
            arr[i][n] = 0;
        } else if (i == 0 && n == 1) {
            arr[i][n] = 2;
        } else if (i == 1 && n == 0) {
            arr[i][n] = 3;
        } else if (n == 0) {
            arr[i][n] = arr[i - 1][n] - arr[i - 2][n] + 1 + arr[i - 1][n];
        } else {
            arr[i][n] = arr[i][n - 1] - arr[i][n - 2] + 1 + arr[i][n - 1];
        }
    }
}

【问题讨论】:

标签: java arrays


【解决方案1】:

好吧,如果您要为该填充模式枚举索引,您会得到

0,0
1,0
0,1
2,0
1,1
0,2
2,1
1,2
2,2

因此,您需要遍历两个索引的 total。也就是加总。如您所见,0,0 总计 0,1,00,1 总计 1,依此类推。给我们这样的东西:

0 1 2
1 2 3
2 3 4

要以这种对角线模式进行迭代,我们可以执行以下操作:

// set up your matrix, any size and shape (MxN) is fine, but jagged arrays will break
int[][] matrix = {{0,0,0},{0,0,0},{0,0,0}};

// number is the value we will put in each position of the matrix
int number = 1;

// iterate while number is less than or equal to the total number of positions
// in the matrix. So, for a 3x3 matrix, 9. (this is why the code won't work for
// jagged arrays)
for (int i = 0; number <= matrix.length * matrix[0].length; i++) {
    // start each diagonal at the top row and from the right
    int row = 0;
    int col = i;

    do {
        // make sure row and length are within the bounds of the matrix
        if (row < matrix.length && col < matrix[row].length) {
            matrix[row][col] = number;
            number++;
        }

        // we decrement col while incrementing row in order to traverse down and left
        row++;
        col--;
    } while (row >= 0);
}

请注意,虽然此实现适用于所有矩阵大小(和形状),但它不会尽可能高效。其中nmatrix.length(假设为方阵),此实现是大O 表示法中的最优O(n^2) 类算法;但是,它有效地执行2*n^2 迭代,而最佳解决方案只会执行n^2

【讨论】:

  • 这里我有一个问题,这是什么算法,或者请提示我如何首先添加到行而不是列?
  • @halu 完成了我的实现。应该适合你。
  • 我刚刚在下面创建了一个O(n^2)。它有一些动态编程方面。它有点乱,可能有更好的写法。但它适用于任何维度。
  • 吹毛求疵:O(2n^2) 是 O(n^2)。常量与大哦符号无关。
  • 是的,@你是对的。但本着全面披露的精神,我想做出区分。
【解决方案2】:

你想要达到这样的目标:

1 2 4 7
3 5 8 B
6 9 C E
A D F G

在大小为 NxN 的网格中,对于网格中的每个点 (x,y),您可以这样确定值(仍然需要对 0 处的偏移进行一些修正,参见最终公式):

  • 如果您在左上半部分,请计算您上方和左侧的三角形面积并加上您与顶部的距离

  • 如果你在右下半部分(或中间),计算你下方和右侧三角形的面积,加上你到底部的距离,然后从整个面积中减去

我们来试试吧:

int N = 4; int[][] v = new[N][N];
for(int y = 0; y < N; y++) for(int x = 0; x < N; x++)
v[x][y] = ( x + y < N ) ?
    ( ( x + y + 1 ) * ( x + y ) / 2 + y + 1 ) :
    ( N * N + 1 - ( N - y ) - ( 2 * N - x - y - 1 ) * ( 2 * N - x - y - 2 ) / 2 );

我不知道这是什么复杂性,但专家肯定可以确认它是 O(N^2) 吗?另外,如果它有一些很酷的名字,比如动态代码,请告诉我!

我在这里看到的优点是您不需要在内存中跳转,并且可以通过内存进行一次线性运行来填充所有字段。还可以将其作为独立于历史的公式由编译器优化或允许更好的并行化。如果你有一台有 N^2 个单位的机器,他们可以在一次操作中计算整个矩阵。

【讨论】:

  • 我喜欢你的解决方案。它确实是 O(n^2) (注意嵌套循环意味着你将执行你的操作 n * n 次)。这与我发布解决方案后的想法相同。
【解决方案3】:

M×N 矩阵的对角线,具有稳健的数组格式

鉴于很多这些答案已经涵盖了基本的 N × N 数组,并且有些非常有效,我继续制作了一个更强大的版本,可以处理 M × N 数组,以及一个漂亮的格式化打印机,用于您自己的享受/自虐观看。

这种方法的效率是O(N^2)。打印机的格式是O(N^2)。

代码

主要

你可以设置任何你想要的行和列,假设是正整数值。

public static void main(String[] args) {
    //create an M x N array
    int rows = 20;  
    int columns = 11;
    int[][] testData = new int[rows][columns];

    //iteratively add numbers
    int counter = 0;
    for(int i = 0; i < rows; i++) {
        for(int j = 0; j < columns; j++)  {
            testData[i][j] = ++counter;
        }
    }

    //print our test array
    printArray(testData);
    System.out.println("");
    //print our diagonal array
    printArray(diagonal(testData));
}

打印二维数组

此方法特别适用于本示例,通过使用 M x N 确定条目数,然后计算位数。例如,如果您想根据数组中最长的项目显示任何大小的数组,您可以轻松地调整此代码来做到这一点。一个体面的挑战最好分配给读者。为此需要 O(N^2),但由于必须在数组中搜索最大值,因此取最大数字的数组本质上需要另一个 O(N^2) 进行搜索。

static void printArray(int[][] array) {
    //get number of digits
    int count = array.length * array[0].length;
    //get power of function
    int power;

    //probably the only time I'd ever end a for loop in a semicolon
    //this gives us the number of digits we need
    //You could also use logs I guess but I'm not a math guy
    for(power = 0; count / Math.pow(10, power) > 1; power++);

    for(int i = 0; i < array.length; i++){
        System.out.print("{");
        for(int j = 0; j < array[0].length; j++){
           //Let's say Power is 0. That means we have a single-digit number, so we need
           // +1 for the single digit. I throw in 2 to make it extra wide
           System.out.print(String.format("%" + Integer.toString(power + 2) 
                   + "s", Integer.toString(array[i][j])));
        }
        System.out.println("}");
     }
}

对角线转换器

当我们考虑 M x N 时,有很多边缘情况需要测试,所以我继续进行,似乎已经涵盖了所有这些情况。不是最整洁的,但看起来很有效。

static int[][] diagonal(int[][] input) {
    //our array info 
    final int numRows = input.length;
    final int numColumns = input[0].length;
    int[][] result = new int[numRows][numColumns];

    //this is our mobile index which we will update as we go through 
    //as a result of certain situations
    int rowIndex = 0;
    int columnIndex = 0;
    //the cell we're currently filling in
    int currentRow = 0;
    int currentColumn = 0;
    for(int i = 0; i < numRows; i++) {
        for(int j = 0; j < numColumns; j++) {
            result[currentRow][currentColumn] = input[i][j];
            //if our current row is at the bottom of the grid, we should
            //check whether we should roll to top or come along
            //the right border
            if(currentRow == numRows - 1) {
                //if we have a wider graph, we want to reset row and
                //advance the column to cascade
                if(numRows < numColumns && columnIndex < numColumns - 1 ) {
                    //move current row down a line
                    currentRow = 0;
                    //reset columns to far right
                    currentColumn = ++columnIndex;
                }
                //if it's a square graph, we can use rowIndex;
                else {
                    //move current row down a line
                    currentRow = ++rowIndex;
                    //reset columns to far right
                    currentColumn = numColumns - 1;
                }
            }
            //check if we've reached left side, happens before the 
            //top right corner is reached
            else if(currentColumn == 0) {
                //we can advance our column index to the right
                if(columnIndex < numColumns - 1) {
                    currentRow = rowIndex;                        
                    currentColumn = ++columnIndex;
                }
                //we're already far right so move down a row
                else {
                    currentColumn = columnIndex;
                    currentRow = ++rowIndex;
                }
            }
            //otherwise we go down and to the left diagonally
            else {
                currentRow++;
                currentColumn--;
            }

        }
    }
    return result;
}

样本输出

Input
{   1   2   3}
{   4   5   6}
{   7   8   9}
{  10  11  12}

Output
{   1   2   4}
{   3   5   7}
{   6   8  10}
{   9  11  12}


Input
{   1   2   3   4   5   6}
{   7   8   9  10  11  12}
{  13  14  15  16  17  18}
{  19  20  21  22  23  24}
{  25  26  27  28  29  30}
{  31  32  33  34  35  36}

Output
{   1   2   4   7  11  16}
{   3   5   8  12  17  22}
{   6   9  13  18  23  27}
{  10  14  19  24  28  31}
{  15  20  25  29  32  34}
{  21  26  30  33  35  36}

Input
{    1    2    3    4    5    6}
{    7    8    9   10   11   12}
{   13   14   15   16   17   18}
{   19   20   21   22   23   24}
{   25   26   27   28   29   30}
{   31   32   33   34   35   36}
{   37   38   39   40   41   42}
{   43   44   45   46   47   48}
{   49   50   51   52   53   54}
{   55   56   57   58   59   60}
{   61   62   63   64   65   66}
{   67   68   69   70   71   72}
{   73   74   75   76   77   78}
{   79   80   81   82   83   84}
{   85   86   87   88   89   90}
{   91   92   93   94   95   96}
{   97   98   99  100  101  102}
{  103  104  105  106  107  108}
{  109  110  111  112  113  114}
{  115  116  117  118  119  120}
{  121  122  123  124  125  126}
{  127  128  129  130  131  132}
{  133  134  135  136  137  138}
{  139  140  141  142  143  144}
{  145  146  147  148  149  150}

Output
{    1    2    4    7   11   16}
{    3    5    8   12   17   22}
{    6    9   13   18   23   28}
{   10   14   19   24   29   34}
{   15   20   25   30   35   40}
{   21   26   31   36   41   46}
{   27   32   37   42   47   52}
{   33   38   43   48   53   58}
{   39   44   49   54   59   64}
{   45   50   55   60   65   70}
{   51   56   61   66   71   76}
{   57   62   67   72   77   82}
{   63   68   73   78   83   88}
{   69   74   79   84   89   94}
{   75   80   85   90   95  100}
{   81   86   91   96  101  106}
{   87   92   97  102  107  112}
{   93   98  103  108  113  118}
{   99  104  109  114  119  124}
{  105  110  115  120  125  130}
{  111  116  121  126  131  136}
{  117  122  127  132  137  141}
{  123  128  133  138  142  145}
{  129  134  139  143  146  148}
{  135  140  144  147  149  150}

【讨论】:

    【解决方案4】:

    卢克的直觉很好——你正在处理上下左右对角线。另一件要注意的是对角线的长度:1、2、3、2、1。我还假设方阵。弄乱你的 for 指标可以产生这样的结果:

        int len = 1;
        int i = 1;
        while(len <= arr.length){
            //Fill this diagonal of length len
            for(int r = 0; r < len; r++){ 
                int c = (len - 1) - r;
                arr[r][c] = i;
                i++;
            }
    
            len++;
        }
        len--; len--;
        while(len > 0){
            //Fill this diagonal of length len
            for(int c = arr.length - 1; c > (arr.length - len - 1); c--){ 
                int r = arr.length - len + 2 - c;
                arr[r][c] = i;
                i++;
            }
    
            len--;
        }
    
        System.out.println(Arrays.deepToString(arr));
    

    【讨论】:

    • 复制代码时计算错误!!
    【解决方案5】:

    这是从 here 翻译成 Java 并针对您的问题进行调整的代码。

    int[][] convertToDiagonal(int[][] input) {
        int[][] output = new int[input.length][input.length];
        int i = 0, j = 0; // i counts rows, j counts columns
    
        int n = input.length;
        for (int slice = 0; slice < 2 * n - 1; slice++) {
            int z = slice < n ? 0 : slice - n + 1;
            for (int k = z; k <= slice - z; ++k) {
                // store slice value in current row
                output[i][j++] = input[k][slice - k];
            }
            // if we reached end of row, reset column counter, update row counter
            if(j == n) {
                j = 0;
                i++;
            }
        }
        return output;     
    }
    

    输入:

    | 1 2 3 |
    | 4 5 6 |
    | 7 8 9 |
    

    输出:

    | 1 2 4 |
    | 3 5 7 |
    | 6 8 9 |
    

    Click here for running test code

    【讨论】:

      【解决方案6】:

      这是一个简单的动态规划 (ish) 解决方案。你基本上是从你所做的最后一步中学习的。

      注意:这是O(N^2)ALGOIRTHM

      初始化:

       int m = 4;
       int n = 4;
       int[][] array = new int[m][n];;
       for(int i = 0; i < 3; i++){
          for(int j = 0; j < 3; j++){
              array[i][j] = 0;
          }
       }
      

      作品:

      array[0][0] = 1;
      for(int i = 0; i < m; i++){
          if(i != 0){ array[i][0] = array[i-1][1]+1;} 
        // This is for the start of each row get 1+ the diagonal 
          for(int j = 1; j < n; j++){
              if(i == 0){
                  array[i][j] = array[i][j-1]+j;
                  // only for the first row, take the last element and add + row Count
              }else{
                  if(i == m-1 && j == n -1){
                     // This is only a check for the last element
                      array[i][j] = array[i][j-1]+1;
                      break;  
                  } 
                  // all middle elements: basically look for the diagonal up right.
                  // if the diagonal up right is out of bounds then take +2 the 
                  // prev element in that row
                  array[i][j] = ((j+1) != (m)) ? array[i-1][j+1] +1: array[i][j-1]+2;
              }
          }
      }
      

      打印解决方案:

       for(int i = 0; i < m; i++){
           for(int j = 0; j < n; j++){
              System.out.print(array[i][j]);
           }
           System.out.println("");
        }
       return 0;
      }
      

      【讨论】:

      • 问题是针对 Java 的。
      【解决方案7】:

      您需要从索引 0..n 转换为 x/y(从 0 到 x*y)并从索引返回到 x/y...

      public void toPos(int index){
          return...
      }
      
      public int toIndex(int x, int y){
          return...
      }
      

      我已经把实现细节留给你了。

      【讨论】:

        【解决方案8】:

        这是针对您的问题的完整工作代码。喜欢就复制粘贴

        public class FillArray{
            public static void main (String[] args){
        
        
            int[][] array = {
                    {1,2,3},
                    {4,5,6},
                    {7,8,9}}; //This is your original array
        
            int temp = 0; //declare a temp variable that will hold a swapped value
        
            for (int i = 0; i < array[0].length; i++){
                for (int j = 0; j < array[i].length; j++){
                    if (i < array.length - 1 && j == array[i].length - 1){ //Make sure swapping only
                        temp = array[i][j];                                //occurs within the boundary  
                        array[i][j] = array[i+1][0];                       //of the array. In this case
                        array[i+1][0] = temp;                              //we will only swap if we are
                    }                                                      //at the last element in each
                }                                                          //row (j==array[i].length-1)
            }                                                              //3 elements, but index starts
                                                                           //at 0, so last index is 2 
          }                                                                   
          }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-05-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多