3 votes

Dessiner un losange de chiffres dans un tableau 2d Java

J'ai résolu quelques questions de codage pour me préparer à un entretien de codage, et j'ai trouvé une question qui m'a semblé assez déroutante. J'ai résolu la question après avoir passé un certain temps dessus ; cependant, le code semble codé en dur et n'a aucun style. Je me demandais donc si je pouvais avoir des retours sur la façon de styliser le code, ou peut-être avoir une meilleure idée de la façon d'aborder le problème.

La question vous demande essentiellement de dessiner un losange de chiffres avec un motif dans un tableau 2d. Elle donne une coordonnée de 'x' et une plage de x. À partir de x, les nombres s'étalent un par un jusqu'à la plage. Il y a donc 4 entrées différentes, N (la taille d'un tableau), X, Y (la coordonnée de 'x' comme (lignes, colonnes)), et R (intervalle).

Si on leur donnait une taille de 8, des coordonnées de (4,5) avec un intervalle de 3, le résultat serait le suivant,

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

Et voici ce que j'ai,

    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++;
    }

Je n'ai pas trouvé d'autre moyen de prendre en charge les nombres diagonaux que d'utiliser quatre boucles while différentes. J'apprécierais tout type de retour d'information. Merci d'avance !

1voto

Robby Cornelissen Points 11222

Vous pouvez simplement boucler sur le tableau une fois, et définir les valeurs en fonction de la distance relative de l'emplacement actuel. (i, j) à la coordonnée fixe (x, j) .

Votre code pourrait ressembler à ceci :

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(", ", " "));
    }
}

Ce qui donne le résultat suivant :

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

Si vous voulez être encore plus concis, vous pouvez remplacer la branche if… else if… else avec des opérateurs ternaires :

array[i][j] = dist == 0 ? 'x' : dist <= r ? (char) (dist + '0') : '0';

1voto

SirRaffleBuffle Points 2121

Voici une méthode assez compacte. A chaque itération i nous remplissons une largeur d'un seul caractère i+1 par i+1 anneau en forme de diamant, centré sur (row, col) avec une valeur i . Pour éviter de remplir l'intérieur du diamant, nous vérifions que la distance de Manhattan à (row, col) est égal à i - ceci n'est vrai que pour les cellules situées à la limite du diamant.

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;
}

Test :

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

Salida:

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

0voto

akmin Points 649

Vous pouvez essayer d'utiliser floodfill, bien que, selon votre niveau, ce soit un peu loin.

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

EDIT : Le code de Robby Cornelissen semble beaucoup plus propre et plus simple que le mien, donc vous devriez probablement vérifier le sien. Cependant, le floodfill est un concept assez important pour la suite, alors autant le vérifier.

L'article est assez long, mais le GIF de l'article est la partie la plus importante.

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();
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X