Pierwszą rzeczą, którą należy zauważyć, jest to, że jeśli tworzysz słowa, wybierając jeden z 3 znaków z każdego z 5 wierszy, kończysz z 3 = łącznie 243 słowa. Bez względu na to, jak zaimplementujesz program, musi on zakończyć budowanie każdego z tych 243 słów.
Rekurencja jest to dobra strategia wdrożenia, ponieważ jasno wynika, że jesteś wybierając jeden z trzech znaków w pierwszym rzędzie, a dla każdego z tych wyborów idziesz na, aby wybrać jeden z trzech znaków w drugim rzędzie , i tak dalej.
W poniższym programie Java pierwsza wersja makeWord
jest funkcją rekursywną, która wybiera znak w wierszu indeksowanym przez currentRowIndex
i dołącza ten znak do wordBuffer
. Jeśli jest to ostatni wiersz, słowo jest kompletne i zostaje dodane do listy słów. W przeciwnym razie funkcja wywołuje się do pracy w wierszu currentRowIndex + 1
.
Należy zauważyć, że bieżący stan wordBuffer
przenosi się do wywołania rekursywnego. Dopiero po powrocie z wywołania rekursywnego usuwamy ostatni znak z wordBuffer
.
Druga wersja makeWord
pozwala przekazać tablicę indeksów wierszy, które określają wiersze, z których chcesz wybierać znaki.Na przykład, aby wybrać postacie z wierszy 1, 3 i 6, można by nazwać:
permuter.makeWord(new int[]{ 1, 3, 6 }, 0);
Można zastąpić to wezwanie w metodzie main
zamiast bieżącej linii, co powoduje, słowo być zbudowany z postaciami z wierszy od 1 do 5:
permuter.makeWord(1, 5);
Jeśli uważnie zapoznać się z metodami makeWord
, zobaczysz, że pierwszy z nich nie recurse gdy ciąg jest kompletna, a drugi raz, a potem recurses zwraca wcześniej, ponieważ position == indices.length
. To drugie podejście jest nieco mniej wydajne, ponieważ kosztuje jeszcze jedno wywołanie rekurencyjne, ale może się okazać, że wyraźniej wyraża ono pojęcie rekurencji. To kwestia gustu.
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();
}
}
Z pewnością nie chcesz używać rekursji. Jest to zdecydowanie problem programowania dynamicznego. Pomyśl o używaniu pętli for – DavidR
Proszę pokazać przykładowe dane wejściowe i wyjściowe, aby problem był lepiej zrozumiały. – luk2302
Zrobiłem tak jak powiedziałeś, czy to wyjaśnia rzeczy? –