Pegar elementos de um vetor e sortear posições em uma matriz

Eu tenho um Vetor[50] e preciso pegar cada uma das posições desse vetor e coloca-los em uma Matriz[10][10] aleatoriamente. As posições tem que pular no máximo 2 espaço entre cada elemento, caso contrario não ira ter espaços suficientes na matriz, ou seja, se o primeiro elemento do vetor vai ficar na posição matriz[0][0] o segundo elemento pode ficar em matriz[0][1], matriz[0][2] ou matriz[0][3].
Consegui fazer até uma parte conforme da pra ver abaixo, preciso de ajuda não sei que método eu uso após sortear a posição usando math.random

Resumo

public class sorteio {
public static void main(String[] args) {
Scanner entrada = new Scanner(System.in);
System.out.println(“Digite uma frase que contenha no máximo 50 caracteres.”)
String frase = entrada.nextLine();
String[] vetor = new String[frase.length];
for (int i = 0; i < frase.length; i++) {
vetor[i] = String.valueOf(frase.charAt(i));
System.out.print(vetor[i]);
}
String[][] matriz = new String[10][10];
int posicao = 0;
for (int i = 0; i < 10; i++) {
for (int j = 0; j < 10; j++) {
posicao = (int) (Math.random() * 3);
matriz[i][j] =
}
}
}
}

O problema de sortear as posições é que cada chamada de Math.random() é “independente”, então pode acabar gerando números repetidos (e aí você teria que verificar se aquela posição já foi sorteada, etc).

Em vez disso, você pode usar outra abordagem. Para exemplificar, vamos supor que a matriz tenha 3 linhas e 4 colunas. As posições dos elementos são conforme abaixo (considerando [linha, coluna], por exemplo, [1, 3] é a posição “linha 1, coluna 3”). Lembrando também que a contagem começa em zero (a primeira linha é zero, a segunda é 1, etc):

[0, 0] [0, 1] [0, 2] [0, 3]
[1, 0] [1, 1] [1, 2] [1, 3]
[2, 0] [2, 1] [2, 2] [2, 3]

Mas também podemos numerar as posições assim:

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

Colocando lado a lado para você ver a correlação entre essas duas formas:

[0, 0] [0, 1] [0, 2] [0, 3]  ->  0   1   2   3   - linha zero
[1, 0] [1, 1] [1, 2] [1, 3]  ->  4   5   6   7   - linha 1
[2, 0] [2, 1] [2, 2] [2, 3]  ->  8   9  10  11   - linha 2
                                 ^   ^   ^   ^
                                 |   |   |   |
                    coluna zero--+   |   |   +--coluna 3
                                     |   |
                           coluna 1--+   +--coluna 2  

E a partir daí podemos derivar uma fórmula para converter de um para outro. Basicamente, a posição 10 está na segunda linha (seria 10 dividido pela quantidade de colunas, arredondado para baixo), e a coluna é o resto da divisão pela quantidade de colunas. Ou seja, dada uma posição pos qualquer, basta fazer:

int linha = pos / colunas;
int coluna = pos % colunas;

Sendo assim, basta gerar um array contendo todas as posições possíveis (basta multiplicar as quantidades de linhas e colunas da matriz, e você tem a quantidade total de posições possíveis). Depois você embaralha este array, e pega somente as N primeiras (no seu caso é 50, o tamanho do vetor), convertendo cada posição para a respectiva linha e coluna. Assim:

String[] vetor = new int[50];
// cria o vetor
for (int i = 0; i < vetor.length; i++) {
    vetor[i] = // etc...
}
// cria a matriz
int qtdLinhas = 10, qtdColunas = 10;
String[][] matriz = new String[qtdLinhas][qtdColunas];

// cria um array contendo todas as posições possíveis da matriz
int[] posicoes = new int[qtdLinhas * qtdColunas];
for (int i = 0; i < posicoes.length; i++) {
    posicoes[i] = i;
}
// embaralha as posições (usa o algoritmo Fisher-Yates: https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle)
Random rnd = new Random();
for (int i = posicoes.length - 1; i > 0; i--) {
    int index = rnd.nextInt(i + 1);
    int a = posicoes[index];
    posicoes[index] = posicoes[i];
    posicoes[i] = a;
}

// pega as primeiras 50 posições
for (int i = 0; i < vetor.length; i++) {
    int pos = posicoes[i];
    // decompõe a posição em linha e coluna
    int linha = pos / qtdColunas;
    int coluna = pos % qtdColunas;
    matriz[linha][coluna] = vetor[i];
}

Assim você evita pegar posições repetidas.

2 curtidas

Obrigado pela ótima explicação.
Infelizmente tenho que seguir conforme o exercício pede, então sou obrigado a usar Math.random. Sobre verificar se a posição já foi usado acho que posso usar algo do tipo ultimaposicao+novosorteio só não sei como colocar isso em java.
Quando os 50 caracteres já estão atribuídos ao vetor e faço o Math.random como posso fazer para pegar o 1º caracter do vetor e atribuir a posição sorteada na matriz?

Ah, esses exercícios e suas limitações artificiais…

Bom, não adianta guardar a última posição, você teria que guardar todas que já foram sorteadas antes para garantir que a nova não é repetida.

Mas um jeito mais simples é inicializar a matriz colocando um valor “inválido” em todas as posições. E cada vez que sortear a posição, só adiciona o valor se ela tiver esse valor “inválido”.

No caso de uma matriz de String, todas as posições por padrão já são inicializadas com null, então você pode verificar se a posição é null (se for, a posição está livre, se não for, já está ocupada e precisa sortear outra):

int qtdLinhas = 10, qtdColunas = 10;
String[][] matriz = new String[qtdLinhas][qtdColunas];
for (int i = 0; i < vetor.length; i++) {
    int linha, coluna;
    do { // enquanto a posição não está livre, continua sorteando
        linha = (int) (Math.random() * qtdLinhas);
        coluna = (int) (Math.random() * qtdColunas);
    } while (matriz[linha][coluna] != null);
    matriz[linha][coluna] = vetor[i];
}

O problema é que quando a matriz já tiver muitas posições ocupadas, vai ficar cada vez mais difícil sortear uma posição livre, e o do/while pode se repetir muitas vezes. Já usando a abordagem anterior, não ocorre esse problema.

Outro detalhe é que o vetor não pode ter nenhum elemento nulo, já que null é o que estamos usando para identificar posições da matriz que estão livres.

1 curtida