|
1 | 1 | package com.freetymekiyan.algorithms.level.hard; |
2 | 2 |
|
3 | | -import java.util.*; |
| 3 | +import java.util.ArrayList; |
| 4 | +import java.util.Arrays; |
| 5 | +import java.util.Collections; |
| 6 | +import java.util.List; |
4 | 7 |
|
5 | 8 | /** |
6 | 9 | * Given a collection of numbers that might contain duplicates, return all |
7 | 10 | * possible unique permutations. |
8 | | - * |
| 11 | + * <p> |
9 | 12 | * For example, |
10 | 13 | * [1,1,2] have the following unique permutations: |
11 | 14 | * [1,1,2], [1,2,1], and [2,1,1]. |
12 | | - * |
| 15 | + * <p> |
13 | 16 | * Tags: Backtracking |
14 | 17 | */ |
15 | 18 | class Permutations2 { |
16 | | - public static void main(String[] args) { |
17 | | - List<List<Integer>> res = permuteUniqueB(new int[]{1, 2, 3}); |
18 | | - for (List<Integer> l : res) System.out.println(l); |
19 | | - } |
20 | | - |
21 | | - /** |
22 | | - * Same idea as Permutation 1 except we skip if duplicate of current element |
23 | | - * is found in previous sequence |
24 | | - */ |
25 | | - public List<List<Integer>> permuteUnique(int[] num) { |
26 | | - List<List<Integer>> res = new ArrayList<List<Integer>>(); |
27 | | - if (num == null || num.length == 0) return res; |
28 | | - Arrays.sort(num); |
29 | | - permute(num, 0, res); |
30 | | - return res; |
| 19 | + |
| 20 | + /** |
| 21 | + * Lexicography Order next permutation |
| 22 | + * Find the next permutation in lexicographic order. |
| 23 | + * http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order |
| 24 | + */ |
| 25 | + public List<List<Integer>> permuteUniqueB(int[] num) { |
| 26 | + List<List<Integer>> res = new ArrayList<>(); |
| 27 | + if (num == null || num.length == 0) return res; |
| 28 | + Arrays.sort(num); |
| 29 | + List<Integer> row = new ArrayList<>(); |
| 30 | + for (int a : num) row.add(a); |
| 31 | + res.add(new ArrayList<>(row)); // first permutation |
| 32 | + while (nextPermutation(row)) { // if there is next permutation |
| 33 | + res.add(new ArrayList<>(row)); |
31 | 34 | } |
32 | | - |
33 | | - public void permute(int[] num, int pos, List<List<Integer>> res) { |
34 | | - if (pos == num.length) { |
35 | | - List<Integer> row = new ArrayList<Integer>(); |
36 | | - for (int a : num) row.add(a); |
37 | | - res.add(row); |
38 | | - return; |
39 | | - } |
40 | | - for (int i = pos; i < num.length; i++) { |
41 | | - // skip if we have duplicates of current element before i |
42 | | - boolean skip = false; |
43 | | - for (int j = pos; j < i; j++) { |
44 | | - if (num[j] == num[i]) { |
45 | | - skip = true; |
46 | | - break; |
47 | | - } |
48 | | - } |
49 | | - if (skip) continue; |
50 | | - swap(num, pos, i); |
51 | | - permute(num, pos + 1, res); |
52 | | - swap(num, pos, i); // reset |
53 | | - } |
| 35 | + return res; |
| 36 | + } |
| 37 | + |
| 38 | + /** |
| 39 | + * e.g.: 1234 -> 1243, 1243 -> 1324 |
| 40 | + * Traverse backward to get 3 |
| 41 | + * Then traverse forward to get furthest number bigger than 3 |
| 42 | + * Swap these two digits and reverse from next to last |
| 43 | + */ |
| 44 | + private boolean nextPermutation(List<Integer> row) { |
| 45 | + int last = row.size() - 1; |
| 46 | + for (int pos = last - 1; pos >= 0; pos--) { |
| 47 | + if (row.get(pos) < row.get(pos + 1)) { |
| 48 | + int smallIdx = pos; |
| 49 | + int biggerIdx = pos + 1; |
| 50 | + for (int i = pos + 1; i <= last; i++) |
| 51 | + if (row.get(i) > row.get(pos)) biggerIdx = i; |
| 52 | + swap(row, smallIdx, biggerIdx); |
| 53 | + reverse(row, pos + 1, last); |
| 54 | + return true; |
| 55 | + } |
54 | 56 | } |
| 57 | + return false; |
| 58 | + } |
| 59 | + |
| 60 | + private void swap(List<Integer> row, int a, int b) { |
| 61 | + int t = row.get(a); |
| 62 | + row.set(a, row.get(b)); |
| 63 | + row.set(b, t); |
| 64 | + } |
55 | 65 |
|
56 | | - public void swap(int[] num, int i, int j) { |
57 | | - if (i == j) return; |
58 | | - num[i] = num[j] - num[i]; |
59 | | - num[j] = num[j] - num[i]; |
60 | | - num[i] = num[j] + num[i]; |
| 66 | + private void reverse(List<Integer> row, int s, int e) { |
| 67 | + while (s < e) { |
| 68 | + swap(row, s, e); |
| 69 | + s++; |
| 70 | + e--; |
61 | 71 | } |
62 | | - |
63 | | - /** |
64 | | - * Lexicography Order next permutation |
65 | | - * Find the next permutation in lexicographic order. |
66 | | - *http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_order |
67 | | - */ |
68 | | - public static List<List<Integer>> permuteUniqueB(int[] num) { |
69 | | - List<List<Integer>> res = new ArrayList<List<Integer>>(); |
70 | | - if (num == null || num.length == 0) return res; |
71 | | - Arrays.sort(num); |
72 | | - List<Integer> row = new ArrayList<Integer>(); |
73 | | - for (int a : num) row.add(a); |
74 | | - res.add(new ArrayList<Integer>(row)); // first permutation |
75 | | - while (nextPermutation(row)) { // if there is next permutation |
76 | | - res.add(new ArrayList<Integer>(row)); |
77 | | - } |
78 | | - return res; |
79 | | - } |
80 | | - |
81 | | - /** |
82 | | - * e.g.: 1234 -> 1243, 1243 -> 1324 |
83 | | - * Traverse backward to get 3 |
84 | | - * Then traverse forward to get furthest number bigger than 3 |
85 | | - * Swap these two digits and reverse from next to last |
86 | | - */ |
87 | | - public static boolean nextPermutation(List<Integer> row) { |
88 | | - int last = row.size() - 1; |
89 | | - for (int pos = last - 1; pos >= 0; pos--) { |
90 | | - if (row.get(pos) < row.get(pos + 1)) { |
91 | | - int smallIdx = pos; |
92 | | - int biggerIdx = pos + 1; |
93 | | - for (int i = pos + 1; i <= last; i++) |
94 | | - if (row.get(i) > row.get(pos)) biggerIdx = i; |
95 | | - swap(row, smallIdx, biggerIdx); |
96 | | - reverse(row, pos + 1, last); |
97 | | - return true; |
98 | | - } |
99 | | - } |
100 | | - return false; |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * Same idea as Permutation 1 except we skip if duplicate of current element |
| 76 | + * is found in previous sequence |
| 77 | + */ |
| 78 | + public List<List<Integer>> permuteUnique(int[] num) { |
| 79 | + if (num == null || num.length == 0) { |
| 80 | + return Collections.emptyList(); |
101 | 81 | } |
102 | | - |
103 | | - public static void swap(List<Integer> row, int a, int b) { |
104 | | - int t = row.get(a); |
105 | | - row.set(a, row.get(b)); |
106 | | - row.set(b, t); |
| 82 | + Arrays.sort(num); |
| 83 | + final List<List<Integer>> res = new ArrayList<>(); |
| 84 | + dfs(num, 0, res); |
| 85 | + return res; |
| 86 | + } |
| 87 | + |
| 88 | + private void dfs(int[] num, int pos, List<List<Integer>> res) { |
| 89 | + if (pos == num.length) { |
| 90 | + final List<Integer> row = new ArrayList<>(num.length); |
| 91 | + for (int a : num) { |
| 92 | + row.add(a); |
| 93 | + } |
| 94 | + res.add(row); |
| 95 | + return; |
107 | 96 | } |
108 | | - |
109 | | - public static void reverse(List<Integer> row, int s, int e) { |
110 | | - while (s < e) { |
111 | | - swap(row, s, e); |
112 | | - s++; |
113 | | - e--; |
| 97 | + for (int i = pos; i < num.length; i++) { |
| 98 | + // Skip if we have duplicates of current element before i |
| 99 | + boolean skip = false; |
| 100 | + for (int j = pos; j < i; j++) { |
| 101 | + if (num[j] == num[i]) { |
| 102 | + skip = true; |
| 103 | + break; |
114 | 104 | } |
| 105 | + } |
| 106 | + if (skip) continue; |
| 107 | + swap(num, pos, i); |
| 108 | + dfs(num, pos + 1, res); |
| 109 | + swap(num, pos, i); // Reset |
| 110 | + } |
| 111 | + } |
| 112 | + |
| 113 | + private void swap(int[] num, int i, int j) { |
| 114 | + if (i == j) { |
| 115 | + return; |
115 | 116 | } |
| 117 | + num[i] = num[j] - num[i]; |
| 118 | + num[j] = num[j] - num[i]; |
| 119 | + num[i] = num[j] + num[i]; |
| 120 | + } |
116 | 121 | } |
0 commit comments