您的位置:首页 > 其它

个人记录-LeetCode 46. Permutations

2016-12-09 20:12 211 查看
问题:

Given a collection of distinct numbers, return all possible permutations.

For example,

[1,2,3] have the following permutations:

[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]


问题要求:得到指定数组的全排列。

代码示例:

1、暴力递归

回忆一下我们通常求全排列的方法。

例如有3个数,它们全排列的大小为:

第1个位置,可以为3个数中的任意一个,共有3种选择;

第2位置,在选完第1个位置的数后,可以为剩下2个数中的任意一个,共有2种选择;

第3个位置,在选完第1个和第2个位置的数后,只有1种选择。

因此,整体共有6种选择。

我们也可以按照这种思路写代码:

public class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();

if (nums == null || nums.length < 1) {
return result;
}

//现将数组排序,这样相同的数字排在一起,可以跳过,避免重复结果
Arrays.sort(nums);

//flag记录一个数字是否被选择过
boolean[] flag = new boolean[nums.length];

//path记录每次排列的结果
List<Integer> path = new ArrayList<>();

//无脑暴力递归
permute(nums, path, flag, result);

return result;
}

private void permute(int[] nums, List<Integer> path, boolean[] flag, List<List<Integer>> result) {
//已经完成了所有位置的选择,返回结果
if (path.size() == nums.length) {
result.add(path);
return;
}

boolean first = true;
//prev记录当前位置,上一次选择的数
int prev = -1;

for (int i = 0; i < nums.length; ++i) {
if (!flag[i]) {
if (first) {
prev = nums[i];
first = false;
} else {
//避免在同一个位置,选择相同的数,避免重复
if (nums[i] == prev) {
continue;
}

prev = nums[i];
}

//生成新的位图
List<Integer> tempList = new ArrayList<>(path);
boolean[] tempFlag = new boolean[nums.length];
System.arraycopy(flag, 0, tempFlag, 0, nums.length);

//添加本次信息
tempFlag[i] = true;
tempList.add(nums[i]);

//继续递归
permute(nums, tempList, tempFlag, result);
}
}
}
}


2、改进

前一种方法选择每个位置的数时,需要判断其它数是否已经被选择过,比较耗费时间。这种过程我们称为“为位置选数”。

下面这个过程,可以称为“为数选位置”。

第1个数与后续每个数交换位置,得到新数组后,在新数组的基础上递归。

此时,第1个数分别放到了0~n-1的位置上。

然后,开始为第2个数选位置。

由于第1个数和第2个数交换过,因此已经有一个递归序列,处理第2个数放到第1个位置的情况了。

为了避免重复,将第2个数与其后的每个数交换位置,得到下一个新数组,然后继续在此基础上递归。

此时,第2个数分别放在了1~n-1的位置上。

以此类推,得到最终结果。

不过这种方式会有重复的结果。

public class Solution {
public List<List<Integer>> permute(int[] nums) {
List<List<Integer>> result = new ArrayList<>();
//仍然排序,避免重复
Arrays.sort(nums);

//迭代
perm(result,nums,0,nums.length-1);

return result;
}

public static void perm(List<List<Integer>> result, int[] nums, int start, int end) {
//start记录此次交换的起始位置
if(start == end){
Integer[] tempNums = new Integer[nums.length];
for (int i = 0; i < nums.length; ++i) {
tempNums[i] = nums[i];
}
result.add(Arrays.asList(tempNums));
} else {
boolean flag = true;
int prev = -1;

for(int i=start; i<=end; i++){
//以下这一段仍是避免重复
if (flag) {
prev = nums[i];
flag = false;
} else {
//prev与nums[i]的比较,与1方法类似,避免重复交换
//nums[start]与nums[i]比较,避免某个位置与起始位置一致
if (prev == nums[i] || nums[start] == nums[i]) {
continue;
} else {
prev = nums[i];
}
}

//交换当前起始位置和后续位置的数
int temp = nums[start];
nums[start] = nums[i];
nums[i] = temp;

//继续迭代
perm(result, nums,start+1,end);

//还原数组
temp = nums[start];
nums[start] = nums[i];
nums[i] = temp;
}
}
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: