EXEMPLO
Dada uma matriz [1,2,3] ou [1,2,3,4], imprimir todas as combinações únicas de comprimento 3.
CÓDIGO
public class PrintCombo {
public void printCombo(int [] a, int [] buffer, int startIndex, int bufferIndex){
printArray(buffer);
if(buffer.length == bufferIndex){
System.out.println();
System.out.println("SOLUTION START");
printArray(buffer);
System.out.println("SOLUTION END");
System.out.println();
return;
}
if(startIndex == a.length){
return;
}
for(int i = startIndex; i<a.length; i++){
buffer[bufferIndex] = a[i];
printCombo(a,buffer,i+1,bufferIndex+1);
}
}
public void printArray(int [] buffer){
for(int i = 0; i<buffer.length; i++){
System.out.print(" "+buffer[i]);
}
System.out.println();
}
}
RESULTADO
Para array [1,2,3] ==> 1,2,3
Para array [1,2,3,4] ==> 1,2,3 || 1,2,4 || 1,3,4 || 2,3,4
Problema
Eu passei 3 horas traçando o código usando um depurador e ainda estou lutando para entender como a lógica recursiva está funcionando.
Por exemplo, vamos dar um exemplo, quando a matriz é [1,2,3].
- PrintCombo (um, tampão, 0, 0)
- tampão [0] é actualizada para uma
- Chamamos PrintCombo (um, tampão, 1, 1)
- tampão de [1] é actualizada para dois
- Chamamos PrintCombo (um, tampão, 2, 2)
- tampão [2] é actualizada para três
- Chamamos PrintCombo (um, tampão, 3, 3)
- Desde buffer.length == bufferIndex chamamos printArray.
- Nós voltar à chamada anterior
Este é o lugar onde eu me perdi. Como é que a pilha de fazer chamadas anteriores? Eu estou tentando difícil de entender essa abordagem completamente quanto eu não gosto de soluções de memorização.
I decidiu editar meu código, adicionando uma declaração de impressão para ver o que está dentro do tampão em cada iteração. Eis o que impresso, por exemplo, a = [1,2,3] e tamanho do buffer é 3.
0 0 0
1 0 0
1 2 0
1 2 3
SOLUTION START
1 2 3
SOLUTION END
1 3 3
2 3 3
2 3 3
3 3 3
Quando inicialmente chamado de loop na printCombo
vontade em cada iteração definir o primeiro elemento buffer
para todos os valores possíveis:
[1,-,-] // i = 0, first iteration
[2,-,-] // i = 1, second iteration
[3,-,-] // i = 2, ...
[4,-,-] // i = 3, ...
Para cada uma dessas iterações há uma chamada recursiva para printCombo
criar todas as combinações possíveis para os elementos restantes buffer
. Por exemplo, na primeira iteração [1,_,_]
é passado para printCombo
, cuja loop irá agora definir o segundo elemento também todos os valores possíveis:
[1,2,-] // i = 0, first iteration in first recursive call to printCombo
[1,3,-] // i = 1, second iteration in first recursive call to printCombo
[1,4,_] // i = 2, ...
O processo continua até que buffer
é cheio (primeiro if
estado) ou a associação de possíveis valores é esgotado (segunda if
condição). No primeiro caso um candidato é encontrada e impresso. No segundo caso um beco sem saída é atingida.
Aqui é a evolução de buffer
tempo ao longo do qual o nível de recuo corresponde à profundidade de recursividade ( a = [1,2,3,4]
e tamanho do buffer 3
):
[1,-,-]
[1,2,-]
[1,2,3] // buffer.length == bufferIndex -> printArray
[1,2,4] // buffer.length == bufferIndex -> printArray
[1,3,-]
[1,3,4] // buffer.length == bufferIndex -> printArray
[1,4,-] // startIndex == a.length -> return
[2,-,-]
[2,3,-]
[2,3,4] // buffer.length == bufferIndex -> printArray
[2,4,-] // startIndex == a.length -> return
[3,-,-]
[3,4,-] // startIndex == a.length -> return
[4,-,-] // startIndex == a.length -> return