无重复项数字全排列
牛客网题目: BM55
思路:
- 创建一个保存最后结果的list
- 新建数组 used 表示num中对应的元素是否被使用过
- 利用path保存排列
- 如果path长度等于num长度则证明一次排列完成,则将其加入res中
- 否则,对数组每一位进行判断是否使用过。若未使用过,则将其加入path,并将其used状态设为true。继续进行递归回溯过程。
代码:
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer>> permute(int[] num) {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
boolean[] used = new boolean[num.length];
dfs(num, new ArrayDeque<>(),res,used);
return res;
}
public void dfs(int[] num,Deque<Integer> path,ArrayList<ArrayList<Integer>> res,boolean[] used){
if(path.size() == num.length){
res.add(new ArrayList<>(path));
return;
}
for(int i = 0;i<num.length;i++){
if(!used[i]){
path.addLast((num[i]));
used[i] = true;
dfs(num,path,res,used);
path.removeLast();
used[i] = false;
}
}
}
}
有重复数字全排列
牛客网题目: BM56
思路:
与无重复排列的区别就在于其存在相同的情况,对其进行筛选。
代码:
import java.util.*;
public class Solution {
public ArrayList<ArrayList<Integer>> permuteUnique(int[] num) {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
Arrays.sort(num);
boolean[] used = new boolean[num.length];
dfs(num,new ArrayDeque<>(),res,used);
return res;
}
public void dfs(int[] num,Deque<Integer> path,ArrayList<ArrayList<Integer>> res,boolean[] used){
if(path.size() == num.length){
res.add(new ArrayList<>(path));
return;
}
for(int i = 0;i<num.length;i++){
if(!used[i]){
//num[i]==num[i - 1]判断是否与上一个遍历值相同,避免重复
//!flag[i - 1] 判断是不是在同个循环体(层)还是嵌套的循环体(不同层)
if (i > 0 && num[i] == num[i - 1] && !used[i - 1])continue;
path.add(num[i]);
used[i]=true;
dfs(num,path,res,used);
path.removeLast();
used[i]=false;
}
}
}
}
下一个排列(蚂蚁面试问到)
- 如果数组是逆序排列的,则直接对数组进行排序得到正序结果即为下一个排列。
- 否则,找到第一个违反逆序的,再找到其右侧比该数大的最小数,进行交换。
- 然后对其右侧数字从小到大排序,即可得到下一个排列。
代码
- 自己的(耗时比官方长)
class Solution {
public void nextPermutation(int[] nums) {
ArrayList<Integer> list = new ArrayList<>();
for(int i = nums.length - 1; i > 0;i--){
// 找到第一个比其前一位大的数
if(nums[i] > nums[i-1]){
int num = nums[i-1];
int min_max = nums[i];
int index_min_max = i;
// 找到比该数大的最小数
for(int j = i + 1;j<nums.length;j++){
if(nums[j] > num && nums[j] < min_max){
min_max = nums[j];
index_min_max = j;
}
}
// 将nums[i-1]的值与min_max的值交换
int temp = nums[i-1];
nums[i-1] = min_max;
nums[index_min_max] = temp;
// 对i至nums.length - 1的数组元素进行排序
Arrays.sort(nums,i,nums.length);
return;
}
}
Arrays.sort(nums);
}
}
- 官方的
class Solution {
public void nextPermutation(int[] nums) {
int i = nums.length - 2;
while (i >= 0 && nums[i] >= nums[i + 1]) {
i--;
}
if (i >= 0) {
int j = nums.length - 1;
while (j >= 0 && nums[i] >= nums[j]) {
j--;
}
swap(nums, i, j);
}
reverse(nums, i + 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 start) {
int left = start, right = nums.length - 1;
while (left < right) {
swap(nums, left, right);
left++;
right--;
}
}
}
字符全排列
BM58字符串的排列
思路
与有重复数字全排列思想一致
代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Deque;
import java.util.ArrayDeque;
public class Solution {
public ArrayList<String> Permutation(String str) {
ArrayList<String> res = new ArrayList<>();
char[] chars = str.toCharArray();
Arrays.sort(chars);
boolean[] used = new boolean[chars.length];
dfs(chars,new ArrayDeque<Character>(),res,used);
return res;
}
public void dfs(char[] chars,Deque<Character> path,ArrayList<String> res,boolean[] used){
if(path.size() == chars.length){
StringBuilder sb = new StringBuilder();
for (Character c:
path) {
sb.append(c);
}
res.add(sb.toString());
return;
}
for(int i = 0;i<chars.length;i++){
if(!used[i]){
if(i > 0 && chars[i] == chars[i-1] && !used[i-1]){
continue;
}
path.add(chars[i]);
used[i] = true;
dfs(chars,path,res,used);
path.removeLast();
used[i] = false;
}
}
}
}