MGT
MGT

Reputation: 173

Find all permutations of non-repeating letters in a word

Given 3 unique letters: can you print the six possible non repeating combinations of the letters, using a recursive function. 'cat' should output: cat, act, atc, tac, tca and cta. Here's my program, I'm having trouble finding the recursive algorithm. Here's my attempt:

 static void findWords(StringBuilder string, int start, int stride) {
    //1. iterate through all possible combinations of the chars recursively

    System.out.println(string);

    if (stride < string.length() && start < string.length())
    {
        char temp = string.charAt(stride);
        string.setCharAt(stride, string.charAt(start));
        string.setCharAt(start, temp);

        findWords(string, start, stride + 1);

        findWords(string, start + 1, stride + 1 );


    }
}

public static void main(String[] args)
{

   StringBuilder word = new StringBuilder("cat");
   findWords(word,0,1);
}

Upvotes: 1

Views: 1645

Answers (3)

javamusings
javamusings

Reputation: 107

The algorithm I used is quite simple. Make each character the first character of the string and find combinations with other two characters. So for the characters c, a, t the combinations would be

c at
c ta

a ct
a tc

t ca
t ac

Code:

static void findWords(String str, int pos) {
    if(str == null || pos < -1) {
        return;
    }

    int len = str.length();
    if(pos + 1 < len) {
        findWords(str, pos + 1);
    }

    //find char swap positions
    int pos1 = (pos + 1) % len;
    int pos2 = (pos - 1 + len) % len;

    char[] chars = str.toCharArray();
    String str1 = new String(new char[] {chars[pos], chars[pos1], chars[pos2]});
    String str2 = new String(new char[] {chars[pos], chars[pos2], chars[pos1]});

    System.out.println(str1);
    System.out.println(str2);
}

public static void main(String[] args) {
    String word = new String("abc");
    findWords(word, 0);
}

Upvotes: 1

geco17
geco17

Reputation: 5294

Here is a full working example with my comments to explain the algorithm.

This solution is based on backtracking. Read more about that here. Look at the problem as a tree. In your example the word is "cat". Here comes some ascii art...

                                      cat
                              /        |        \
                            Cat       Act       Tca 
                           /   \     /   \     /   \
                          CAt CTa   ACt ATc   TCa TAc

At each pass, you fix a letter (I put it as a capital). The further down the tree you get the less there is that you can swap because you've fixed a certain amount of letters in place (at level 0 nothing is fixed, at level 1, one letter is fixed so a swap can be done, at level 2 you have no more swaps (the swap would be with itself), so the recursion reaches its base case.

public static void main(String[] args) {
    // get all the permutations of a word with distinct letters
    Set<String> permutations = getPermutations("cat");

    // print the resulting set
    System.out.println(permutations);
}

private static Set<String> getPermutations(String string) {
    // recursive call to get a permutation of the given string and put it in
    // the set of permutations (initially empty)
    return permute(string, 0, string.length() - 1, new HashSet<String>());
}

private static Set<String> permute(String string, int left, int right, Set<String> set) {
    if (left == right) {
        // swap would be with itself so just add the string
        // this is the base case
        set.add(string);
    } else {
        for (int i = left; i <= right; i++) {
            // indices are different, something can be swapped so swap it
            string = swap(string, left, i);
            // permute the swapped string starting from the next available character
            permute(string, left + 1, right, set);
        }
    }
    return set;
}

// utility method to carry out the swapping
// you could do this with primitive char[] and probably improve performance
// but for the sake of simplicity as it's just an exercise I used a 
// StringBuilder
private static String swap(String in, int i, int j) {
    char tmp1 = in.charAt(i);
    char tmp2 = in.charAt(j);
    StringBuilder sb = new StringBuilder(in);
    // put the char at j in place of the char at i
    sb.setCharAt(i, tmp2);
    // and do the same the other way around
    sb.setCharAt(j, tmp1);

    return sb.toString();
}

Upvotes: 0

Coder-Man
Coder-Man

Reputation: 2531

Solution:

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

    static List<String> resultList = new ArrayList<>();

    static void computeResult(char[] s, int pos, String resultString) {
        if (pos == 3) {
            resultList.add(resultString);
            return;
        }
        for (int i = 0; i < 3; ++i) {
            if (!resultString.contains(String.valueOf(s[i]))) {
                computeResult(s, pos + 1, resultString + s[i]);
            }
        }
    }

    public static void main(String... args) {
        Scanner sc = new Scanner(System.in);
        char[] s = sc.next().toCharArray();
        sc.close();
        computeResult(s, 0, "");
        for(String str : resultList) {
            System.out.println(str);
        }
    }
}

Explanation:

The recursion is done by the computeResult function. It starts with an empty string, then it iterates through all possible letters 'c', 'a' and 't', appending them to the resultString, now there are 3 strings and for each one of them the function computeResult is called again. Then it does the same thing and also adds only those letters to the resultString that haven't been added yet, so to 'c' we append 'a' resulting in 'ca' and 't', resulting in 'ct', I think the rest you can figure out yourself.

Note than this works if the letters are unique. If they are not, for example you are given the string 'tat', you can transform it into t1a1t2 and do the same procedure for the array ['t1', 'a1', 't2'], then remove the digits.

Upvotes: 1

Related Questions