The first thing to notice is that if you make words by choosing one of 3 characters from each of 5 lines, you will end up with 3 5 = 243 words. No matter how you implement the program, it must create each of these 243 words.
Recursion is a good implementation strategy because it makes it clear that you are choosing one of the three characters in the first line, and for each of these options you are choosing one of the three characters in the second line, etc.
In the Java program below, the first version of makeWord is a recursive function that selects a character in the string indexed by currentRowIndex and adds that character to wordBuffer . If this is the last line, the word is completed and added to the list of words. Otherwise, the function calls itself to work on the currentRowIndex + 1 .
Note that the current state of wordBuffer carried over to the recursive call. Only after returning from the recursive call, we remove the last character from wordBuffer .
The second version of makeWord allows makeWord to pass an array of string indices that determine which strings you want to select characters from. For example, to select characters from lines 1, 3, and 6, you would call:
permuter.makeWord(new int[]{ 1, 3, 6 }, 0);
You can replace this call in the main method instead of the current line, which forces the word to build with characters from lines 1 to 5:
permuter.makeWord(1, 5);
If you look closely at the makeWord methods, you will see that the first does not recurs when the line is completed, and the second repeats once, and then returns earlier, because position == indices.length . The latter approach is slightly less efficient, as it requires another recursive call, but you may find that it more clearly expresses the concept of recursion. This is a matter of taste.
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(); } }