Moritz Wolff
Moritz Wolff

Reputation: 508

Return all permutations of a given list recursively

The following algorithm prints all permutations of a given list arr:

public class Permute {
    static void permute(java.util.List<Integer> arr, int k) {
        for (int i = k; i < arr.size(); i++) {
            java.util.Collections.swap(arr, i, k);
            permute(arr, k + 1);
            java.util.Collections.swap(arr, k, i);
        }
        if (k == arr.size() - 1) {
            System.out.println(java.util.Arrays.toString(arr.toArray()));
        }
    }

    public static void main(String[] args) {
        Permute.permute(java.util.Arrays.asList(1, 2, 3), 0);
    }
}

(FYI: The algorithm is taken from this answer)

I would like to modify the algorithm so that it returns a list of all solutions instead of printing them, i.e. something like:

static List<List<Integer>> permute(java.util.List<Integer> arr, int k);

How would I do this? I tried the following modification of the algorithm, but it didn't work:

public class Permute {
    static List<List<Integer>> permute(java.util.List<Integer> arr, int k) {
        List<List<Integer>> arrs = new ArrayList<>();
        for (int i = k; i < arr.size(); i++) {
            java.util.Collections.swap(arr, i, k);
            arrs.addAll(permute(arr, k + 1));
            java.util.Collections.swap(arr, k, i);
        }
        if (k == arr.size() - 1) {
            arrs.add(arr);
            System.out.println(java.util.Arrays.toString(arr.toArray()));
        }
        return arrs;
    }

    public static void main(String[] args) {
        List<Integer> arr = new ArrayList<>(Arrays.asList(1, 2, 3));
        System.out.println(Permute.permute(arr, 0));
    }
}

The code compiles and executes, but gives the wrong result of [[1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3], [1, 2, 3]]. I'm having trouble seeing why the code doesn't work and how to do it correctly. Any help is appreciated.

Upvotes: 1

Views: 659

Answers (2)

RaffleBuffle
RaffleBuffle

Reputation: 5455

As Unmitigated has pointed out, you need to add a copy of the permuted list.

Also, there's no need to create a new list to hold permutations at each level of the recursion. You could create a single list to hold the results and pass it as an argument:

static void permute(List<List<Integer>> res, List<Integer> arr, int k) {
  if (k == arr.size() - 1) {
    res.add(new ArrayList<>(arr));
    return;
  }

  for (int i = k; i < arr.size(); i++) {
    Collections.swap(arr, i, k);
    permute(res, arr, k + 1);
    Collections.swap(arr, k, i);
  }
}

public static void main(String[] args) {
  List<List<Integer>> res = new ArrayList<>();
  permute(res, Arrays.asList(1, 2, 3), 0);
  System.out.println(res);
}

Upvotes: 1

Unmitigated
Unmitigated

Reputation: 89139

You need to add a copy of the List to the result instead of adding the same one each time.

Change

arrs.add(arr);

To

arrs.add(new ArrayList<>(arr));

Full method:

static List<List<Integer>> permute(java.util.List<Integer> arr, int k) {
    List<List<Integer>> arrs = new ArrayList<>();
    for (int i = k; i < arr.size(); i++) {
        java.util.Collections.swap(arr, i, k);
        arrs.addAll(permute(arr, k + 1));
        java.util.Collections.swap(arr, k, i);
    }
    if (k == arr.size() - 1) {
        arrs.add(new ArrayList<>(arr));
    }
    return arrs;
}

Demo

Upvotes: 1

Related Questions