代码之家  ›  专栏  ›  技术社区  ›  vaska11

在二维数组Java中绘制数字菱形

  •  3
  • vaska11  · 技术社区  · 6 年前

    我一直在解决一些编码问题,以便为编码面试做好准备,并发现了一个似乎有些令人费解的问题。我花了一些时间解决了这个问题;但是,代码看起来是硬编码的,没有样式。所以,我想知道我是否能得到一些关于代码样式的反馈,或者也许能得到一个更好的解决问题的想法。

    这个问题基本上要求你画一个二维数组中有图案的菱形数字。 它给出了x的坐标和x的范围。从x开始,数字一个接一个地扩散到范围。所以,有4个不同的输入,N(数组的大小),X,Y(X的坐标,as(行,cols))和R(范围)。

    如果给他们一个8的大小,坐标(4,5)和3的范围,结果会是,

    0 0 0 0 3 0 0 0
    0 0 0 3 2 3 0 0
    0 0 3 2 1 2 3 0
    0 3 2 1 x 1 2 3
    0 0 3 2 1 2 3 0
    0 0 0 3 2 3 0 0
    0 0 0 0 3 0 0 0
    0 0 0 0 0 0 0 0
    

    下面是我所拥有的,

        int n = sc.nextInt();
        char[][] arr = new char[n][n];
        int r = sc.nextInt() - 1;
        int c = sc.nextInt() - 1;
        int range = sc.nextInt();
    
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                arr[i][j] = '0';
            }
        }
    
        arr[r][c] = 'x';
    
    
        int num = 1;
        for (int i = 0; i < range; i++) {
            //Cross
            if (c-num > -1) {
                arr[r][c - num] = (char) (num + '0');
            }
            if (c+num < n) {
                arr[r][c + num] = (char) (num + '0');
            }
            if (r-num > -1) {
                arr[r - num][c] = (char) (num + '0');
            }
            if (r+num < n) {
                arr[r + num][c] = (char) (num + '0');
            }
            //Diagonal
            if (i > 0) {
                int sum = num - 1, delta = 1;
    
                while (sum != 0) {
                    if (r-sum > -1 && c+delta < n) {
                        arr[r - sum][c + delta] = (char) (num + '0');
                    }
                    sum--;
                    delta++;
                }
                sum = num - 1; delta = 1;
                while (sum != 0) {
                    if (r+sum < n && c-delta > -1) {
                        arr[r + sum][c - delta] = (char) (num + '0');
                    }
                    sum--;
                    delta++;
                }
                sum = num - 1; delta = 1;
                while (sum != 0) {
                    if (r-sum > -1 && c-delta > -1) {
                        arr[r - sum][c - delta] = (char) (num + '0');
                    }
                    sum--;
                    delta++;
                }
                sum = num - 1; delta = 1;
                while (sum != 0) {
                    if (r+sum < n && c+delta > -1) {
                        arr[r + sum][c + delta] = (char) (num + '0');
                    }
                    sum--;
                    delta++;
                }
            }
            num++;
        }
    

    除了使用四个不同的while循环,我想不出其他方法来处理对角线数字。我希望能得到任何反馈。提前谢谢!

    3 回复  |  直到 6 年前
        1
  •  1
  •   Robby Cornelissen    6 年前

    只需在数组上循环一次,然后根据当前位置的相对距离设置值 (i, j) 到固定坐标 (x, j) .

    您的代码可能如下所示:

    import java.util.Arrays;
    
    public class Test {
        public static void main(String[] args) {
            // variables
            int n = 8;
            int x = 4 - 1; // coordinates are one-based
            int y = 5 - 1; // coordinates are one-based
            int r = 3;
            char[][] array = new char[n][n];
    
            // logic
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    int dist = Math.abs(x - i) + Math.abs(y - j); // calculate distance
    
                    if(dist == 0) {         // at x,y
                        array[i][j] = 'x';
                    } else if (dist <= r) { // distance to x,y is within range
                        array[i][j] = (char) (dist + '0');
                    } else {                // distance to x,y is outside of range
                        array[i][j] = '0';
                    }
                }
            }
    
            // dump output
            System.out.println(Arrays.deepToString(array)
                               .replace("], ", "]\n")
                               .replace("[", "")
                               .replace("]", "")
                               .replace(", ", " "));
        }
    }
    

    产生以下输出:

    0 0 0 0 3 0 0 0
    0 0 0 3 2 3 0 0
    0 0 3 2 1 2 3 0
    0 3 2 1 x 1 2 3
    0 0 3 2 1 2 3 0
    0 0 0 3 2 3 0 0
    0 0 0 0 3 0 0 0
    0 0 0 0 0 0 0 0
    

    如果你想更加简洁,你可以替换分支 if… else if… else 三元运算符语句:

    array[i][j] = dist == 0 ? 'x' : dist <= r ? (char) (dist + '0') : '0';
    
        2
  •  0
  •   akmin    6 年前

    你可以尝试使用洪水填充,尽管根据你的水平可能有点远。

    https://en.wikipedia.org/wiki/Flood_fill

    编辑:Robby Cornelissen的代码看起来比我的更干净和简单,所以你应该看看他的代码。然而,洪水填充是一个相当重要的概念,为以后,所以不妨看看它。

    文章很长,但文章中的GIF是最重要的部分。

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.Queue;
    import java.util.StringTokenizer;
    
    public class test {
    
        public static void main(String[] args) throws IOException {
            //Get inputs (I used BufferedReader, Scanner works fine as well)
            //My inputs are formatted as 'N X Y R' (ex. '8 4 5 3')
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
            StringTokenizer st = new StringTokenizer(br.readLine(), " ");
            int N = Integer.parseInt(st.nextToken());
            int R = Integer.parseInt(st.nextToken()) - 1;
            int C = Integer.parseInt(st.nextToken()) - 1;
            int range = Integer.parseInt(st.nextToken());
            char[][] arr = new char[N][N];
    
            //Make everything in array '0'
            for (int i = 0; i < N; i++) {
                Arrays.fill(arr[i], '0');
            }
    
            //Floodfill using BFS
            //FYI: this BFS is iterative, not recursive
            Queue<int[]> q = new LinkedList<>();
            q.add(new int[]{0, R, C});
            while (!q.isEmpty()) {
                int[] current = q.remove();
                if (arr[current[1]][current[2]] == '0' && current[0] <= range) {
                    arr[current[1]][current[2]] = (current[0]+"").charAt(0);
                    if(current[1]+1 < N) q.add(new int[]{current[0]+1, current[1]+1, current[2]});
                    if(current[1]-1>= 0) q.add(new int[]{current[0]+1, current[1]-1, current[2]});
                    if(current[2]+1 < N) q.add(new int[]{current[0]+1, current[1], current[2]+1});
                    if(current[2]-1>= 0) q.add(new int[]{current[0]+1, current[1], current[2]-1});
                }
            }
            arr[R][C] = 'x';
    
            //Print out the final grid
            for (int i = 0; i < N; i++) {
                for (int j = 0; j< N; j++) {
                    System.out.print(arr[i][j] + " ");
                }
                System.out.println();
            }
        }
    }
    
        3
  •  0
  •   RaffleBuffle    6 年前

    这里有一个相当简洁的方法。每次迭代时 i 我们把一个字符填宽 i+1 通过 i+1 菱形环,居中 (row, col) ,有价值 . 为了避免填充钻石内部,我们检查曼哈顿距离 (行,列) 等于 -这只适用于菱形边界上的单元格。

    static char[][] buildDiamond(int n, int row, int col, int range)
    {
      char[][] arr = new char[n][n];
      for(char[] a : arr) Arrays.fill(a, '0');
      arr[row][col] = 'x';
    
      for(int i=1; i<=range; i++)
        for(int j=0; j<=i; j++)
          for(int k=0; k<=i; k++)
            if(Math.abs(k-j) + Math.abs(k+j-i) == i)
              arr[row+k-j][col+k+j-i] += i;
    
      return arr;
    }
    

    测试:

    public static void main(String[] args)
    {
      for(char[] a : buildDiamond(7, 3, 3, 3)) 
        System.out.println(new String(a).replaceAll(".", "$0 "));
    }
    

    输出:

    0 0 0 3 0 0 0 
    0 0 3 2 3 0 0 
    0 3 2 1 2 3 0 
    3 2 1 x 1 2 3 
    0 3 2 1 2 3 0 
    0 0 3 2 3 0 0 
    0 0 0 3 0 0 0