La prima cosa da osservare è che se si stanno facendo le parole selezionando uno dei 3 caratteri da ciascuna delle 5 righe, si termina con 3 = 243 parole in totale. Indipendentemente da come si implementa il programma, deve finire per costruire ognuna di quelle 243 parole.
La ricorsione è una buona strategia di implementazione perché rende chiaro che si sta selezionando uno dei tre caratteri nella prima riga e per ciascuna di queste opzioni si seleziona uno dei tre caratteri nella seconda riga , e così via.
Nel programma Java seguente, la prima versione di makeWord
è una funzione ricorsiva che seleziona un carattere nella riga indicizzata da currentRowIndex
e aggiunge tale carattere a wordBuffer
. Se questa è l'ultima riga, la parola è completa e viene aggiunta ad un elenco di parole. In caso contrario, la funzione si chiama per funzionare sulla riga currentRowIndex + 1
.
Si noti che lo stato corrente di wordBuffer
viene trasferito alla chiamata ricorsiva. Solo dopo il ritorno dalla chiamata ricorsiva eliminiamo l'ultimo carattere da wordBuffer
.
La seconda versione di makeWord
consente di passare una matrice di indici di riga che specifica da quali righe si desidera selezionare i caratteri.Ad esempio, per selezionare i caratteri da righe 1, 3 e 6, si potrebbe chiamare:
permuter.makeWord(new int[]{ 1, 3, 6 }, 0);
è possibile sostituire quella chiamata nel metodo al posto della riga corrente main
, che provoca una parola da costruire con i personaggi da righe da 1 a 5:
permuter.makeWord(1, 5);
Se si dà un'occhiata da vicino i metodi makeWord
, vedrete che il primo non recurse quando la stringa è completa, mentre il secondo recurses una volta e poi ritorna presto perché position == indices.length
. Quest'ultimo approccio è leggermente meno efficiente perché costa un altro richiamo ricorsivo, ma potreste scoprire che esprime più chiaramente il concetto di ricorsione. È una questione di gusti.
import java.util.*;
public class PermuteCharacters {
char[][] rows = {
{},
{'A','B','C'},
{'D','E','F'},
{'G','H','I'},
{'J','K','L'},
{'M','N','O'},
{'P','R','S'},
{'T','U','V'},
{'W','X','Y'}
};
StringBuffer wordBuffer = new StringBuffer();
ArrayList<String> words = new ArrayList<String>();
void makeWord(int currentRowIndex, int endRowIndex) {
char[] row = rows[currentRowIndex];
for (int i = 0; i < row.length; ++i) {
wordBuffer.append(row[i]);
if (currentRowIndex == endRowIndex) {
words.add(wordBuffer.toString());
} else {
makeWord(currentRowIndex + 1, endRowIndex);
}
wordBuffer.deleteCharAt(wordBuffer.length() - 1);
}
}
void makeWord(int[] indices, int position) {
if (position == indices.length) {
words.add(wordBuffer.toString());
return;
}
char[] row = rows[indices[position]];
for (int i = 0; i < row.length; ++i) {
wordBuffer.append(row[i]);
makeWord(indices, position + 1);
wordBuffer.deleteCharAt(wordBuffer.length() - 1);
}
}
void displayWords() {
if (words.size() != 0) {
System.out.print(words.get(0));
for (int i = 1; i < words.size(); ++i) {
System.out.print(" " + words.get(i));
}
System.out.println();
}
System.out.println(words.size() + " words");
}
public static void main(String[] args) {
PermuteCharacters permuter = new PermuteCharacters();
permuter.makeWord(1, 5);
permuter.displayWords();
}
}
Non si vuole assolutamente usare la ricorsione. Questo è sicuramente un problema di programmazione dinamica. Pensa in termini di utilizzo di un ciclo for – DavidR
per favore mostra alcuni esempi di input e output per rendere il problema più comprensibile – luk2302
Ho fatto come hai detto, questo chiarisce le cose? –