全排列
1.无重复数字全排列
leetcode 46
题目:
Given a collection of distinct integers, return all possible permutations.
Example:
Input: [1,2,3]
Output:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
思路:DFS深搜,每次从候选集中选择一个加入,创建visited数组存储该数字是否已被访问。
import java.util.ArrayList;
import java.util.List;
public class Solution {
List<List<Integer>> list = new ArrayList<>();
boolean[] visited;
public List permute(int[] nums){
if(nums.length == 0) return list;
visited = new boolean[nums.length];
List<Integer> temp = new ArrayList<>();
helper(nums, temp);
return list;
}
public void helper(int[] nums, List<Integer> temp){
if(temp.size() == nums.length) {
//new一个tmp用来加入list
List<Integer> tmp = new ArrayList<>(temp);
list.add(tmp);
return;
}
for(int i = 0; i < nums.length; i++){
if(visited[i])
continue;
temp.add(nums[i]);
visited[i] = true;
helper(nums, temp);
temp.remove(temp.size()-1);
visited[i] = false;
}
}
}
时间复杂度 O(N)
,空间复杂度 O(N)
2.有重复数字的全排列
leetcode 47
题目:
Given a collection of numbers that might contain duplicates, return all possible unique permutations.
Example:
Input: [1,1,2]
Output:
[
[1,1,2],
[1,2,1],
[2,1,1]
]
思路:同DFS深搜,防止重复数字使结果重复要使同一个位置每个不同数字只选中1次。首先给数组排序,遇到连续相等数字跳过即可。
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
//DFS
List<List<Integer>> list = new ArrayList<>();
boolean[] visited;
public List permute(int[] nums){
if(nums.length == 0) return list;
//数组排序
Arrays.sort(nums);
visited = new boolean[nums.length];
List<Integer> temp = new ArrayList<>();
helper(nums, temp);
return list;
}
public void helper(int[] nums, List temp){
if(temp.size() == nums.length){
List<Integer> tmp = new ArrayList<>(temp);
list.add(tmp);
return;
}
for (int i = 0; i < nums.length; i++) {
if(visited[i])
continue;
temp.add(nums[i]);
visited[i] = true;
helper(nums, temp);
temp.remove(temp.size()-1);
visited[i] = false;
//相邻相同数字跳过
while(i < nums.length-1 && nums[i] == nums[i+1])
i++;
}
}
}
时间复杂度 O(N)
,空间复杂度 O(N)
3.全排列下一个
leetcode 31
题目:
Implement next permutation, which rearranges numbers into the lexicographically next greater permutation of numbers.
If such arrangement is not possible, it must rearrange it as the lowest possible order (ie, sorted in ascending order).
The replacement must be in-place and use only constant extra memory.
Here are some examples. Inputs are in the left-hand column and its corresponding outputs are in the right-hand column.
1,2,3 → 1,3,2
3,2,1 → 1,2,3
1,1,5 → 1,5,1
思路:
假定一序列现在为<3, 5, 9, 7, 4>
,其下一个全排列应为<3, 7, 4, 5, 9>
。观察后三位<9, 7, 4>
的逆序组合已经不能更大,因此要向前把5加入让序列变得更大,让比5大的最小数7与5互换位置,这时变为<3, 7, 9, 5, 4>
可见后面仍然为逆序,要使得此序列在7以后为最小,故将逆序翻转即可。
import java.util.Arrays;
public class Solution {
public void nextPermutation(int[] nums){
if(nums.length <= 1) return;
int i = nums.length - 2;
//寻找逆序结束位置
while(i >= 0 && nums[i] >= nums[i+1]){
i--;
}
if(i >= 0){
//寻找逆序中比i大的最小数与i互换位置
int j = nums.length - 1;
while(j > i && nums[j] <= nums[i]){
j--;
}
swap(nums, i, j);
}
//若i<0说明整个数组为逆序,全部翻转输出最小值
//逆序翻转
reverse(nums, i+1, nums.length-1);
}
public void swap(int[] nums, int i, int j){
int temp = nums[i];
nums[i] = nums[j];
nums[j] = temp;
}
public void reverse(int[] nums, int left, int right){
while(left < right){
swap(nums, left, right);
left++;
right--;
}
}
时间复杂度 O(N)
,空间复杂度 O(1)
4.全排列序列
leetcode 60
题目:
The set [1,2,3,...,*n*]
contains a total of n! unique permutations.
By listing and labeling all of the permutations in order, we get the following sequence for n = 3:
"123"
"132"
"213"
"231"
"312"
"321"
Given n and k, return the kth permutation sequence.
Note:
- Given n will be between 1 and 9 inclusive.
- Given k will be between 1 and n! inclusive.
Example 1:
Input: n = 3, k = 3
Output: "213"
Example 2:
Input: n = 4, k = 9
Output: "2314"
思路:
假定现n=4, k=15, 输出应为 <3214>
。
将其分解成组:
第一组:1 + <234>的全排列
第二组:2 + <134>的全排列
第三组:3 + <124>的全排列
第四组:4 + <123>的全排列
因3个数的全排列个数为 3! = 6
个,利用取模的运算性质可以得到 k-1 / 6 = 2 mod 2
位于第三组。
将k重新赋值为余数2, 继续在 <124>
的全排列中找到下一个数字的过程即得到结果。
import java.util.ArrayList;
import java.util.List;
public class Solution {
public String getPermutation(int n, int k) {
String ans = "";
int mod = 1;
//创建nums存储备选数字
List<Integer> nums = new ArrayList<>();
for(int i=1; i<=n; i++){
mod *= i;
nums.add(i);
}
//开始除法取模操作,先-1
k--;
for(int i=0; i<n; i++){
mod = mod / (n-i);
//在候选集中取出这一位的数字
int turn = k / mod;
k %= mod;
ans += nums.get(turn);
//将其从候选集中删除
nums.remove(turn);
}
return ans;
}
}
时间复杂度 O(N)
,空间复杂度 O(1)