Given a collection of distinct numbers, return all possible permutations.
[1,2,3]
[ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3,2,1] ]
最直观的方法就是插入法,可以在头,中间,尾每个有空隙的地方插入元素。
基本操作是Arrays.add(num, pos), 该操作时间复杂度是O(n). 因为pos以后的元素要移位。最终结果的时间复杂度就是O(n*n!), n!个排列,没个插入的时间复杂度是O(n).
另一种方法是swap。基于位置,swap(nums, i, j)时间复杂度是O(1). 所以我们选择时间复杂度小的。
public class Solution {
public List<List<Integer>> permute(int[] nums) {
// corner case, empty input
List<List<Integer>> res = new ArrayList<List<Integer>>();
permutating(nums, res, 0);
return res;
}
public void permutating(int[] nums, List<List<Integer>> res, int start){
if(start == nums.length) {
List<Integer> list = new ArrayList<Integer>();
for(int n:nums){
list.add(n);
}
res.add(list);
return;
}
for(int i=start; i<nums.length; i++){
swap(nums, start, i);
permutating(nums, res, start+1);
swap(nums, start, i);
}
}
public void swap(int[] nums, int i , int j) {
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
如果输入有重复怎么办。
我们可以利用Set, 可以在输出结果的时候比较是否有重复的结果。
我们也可以在每次swap的时候比较nums[i], nums[j]是否相同。
set比较的是两个长度为O(n)的数组, swap比较的是两个元素。显然,选择长度短的。
这里有两个需要注意的地方,第一要先sort, 第二传入的数组需要copy一个新的。这两个步骤都是在避免,swap 的顺序不同,可能产生相同的permutation.
请手动[1,1,2,2]的每一步,就会发现重复的。
public class Solution {
public List<List<Integer>> permuteUnique(int[] nums) {
List<List<Integer>> res = new ArrayList<List<Integer>>();
if(nums == null) return null;
Arrays.sort(nums);
permutating(nums, res, 0);
return res;
}
public void permutating(int[] nums, List<List<Integer>> res, int start){
if(start == nums.length) {
List<Integer> list = new ArrayList<Integer>();
for(int n:nums){
list.add(n);
}
res.add(list);
return;
}
// [1,1,2,2] different swap steps, may lead to same permutation
for(int i=start; i<nums.length; i++){
if(i != start && nums[i] == nums[start]) { // skip same element
continue;
}
swap(nums, start, i);
permutating(Arrays.copyOf(nums, nums.length), res, start+1);
}
}
public void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
}
Generate all permutations in lexicographical order
i = 0 i = 1 i = 2 i=3(output)
abc -> abc -> abc -> abc
acb <- return <- return
reverse(1,2) to abc
abc swap(0,1) to next greater bac
bac -> bac -> bac -> bac
bca <- return
reverse(1,2) to bac
bac swap(0,2) to cab
cab -> ...
大致思路是找到第一个升续的组合,然后不断从后向前产生下一个更大的组合。
import java.util.*;
import java.io.*;
public class Solution{
public List<String> permutation(String s){
List<String> res = new ArrayList<String>();
if(s == null || s.length() == 0) return res;
char[] arr = s.toCharArray();
Arrays.sort(arr);
dfs(arr, 0, arr.length);
return res;
}
public void dfs(char[] arr, int i, int n){
if(i == n){
StringBuilder sb = new StringBuilder();
for(char c : arr){
sb.append(c);
}
System.out.println(sb.toString());
return;
}
for(int j = i; j < n; j++){
dfs(arr, i+1, n); // 在这里直接dfs走下去是用到recursion的方法。
reverse(arr, i+1, n - 1); // 为了还原到初始位置。
int k = i+1;
while(k < n && arr[i] > arr[k]){ // 找到下一个更大的字符.
k++;
}
if(k >= n) continue;
swap(arr, i, k);
}
reverse(arr, i + 1, n - 1);
}
public void swap(char[] arr, int i, int j){
char t = arr[i];
arr[i] = arr[j];
arr[j] = t;
}
public void reverse(char[] arr, int i, int j){
while(i < j){
swap(arr, i++, j--);
}
}
public static void main(String[] args){
Solution sol = new Solution();
String s = "abc";
List<String> res = sol.permutation(s);
System.out.println(res.size());
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。