Acwing842全排列--------换一种形式(C++版)
进阶的47题(含重复元素的题解地址):
https://blog.csdn.net/qq_52934831/article/details/119578852
Acwing842全排列--------换一种形式(C++版)
描述:
代码:
#include <iostream>
using namespace std;
int n;
//1<=n<=7
const int N=8;
bool exist[N];
int temp[N];
//len代表在第几层
void dfs(int len){
if(len==n){
//依次输出每层上的数
for(int i=0;i<n;i++) cout<<temp[i]<<" ";
cout<<endl;
return;
}
for(int i=1;i<=n;i++){
if(!exist[i]){
exist[i]=true;
temp[len]=i;
dfs(len+1);
temp[len]=0;
exist[i]=false;
}
}
}
int main(){
cin>>n;
dfs(0);
return 0;
}
地址:
https://leetcode-cn.com/problems/permutations/
描述:
题解(这个大佬讲的很仔细):
解题心路历程:
开始的时候,我对于回溯算法的调用不是很理解,不知道它走到具体哪一步,该怎么走,直到我看到了上面这个老哥的题解。
这是他的代码易于我们去观察:
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.List;
public class Solution {
public List<List<Integer>> permute(int[] nums) {
int len = nums.length;
// 使用一个动态数组保存所有可能的全排列
List<List<Integer>> res = new ArrayList<>();
if (len == 0) {
return res;
}
boolean[] used = new boolean[len];
Deque<Integer> path = new ArrayDeque<>(len);
dfs(nums, len, 0, path, used, res);
return res;
}
private void dfs(int[] nums, int len, int depth,
Deque<Integer> path, boolean[] used,
List<List<Integer>> res) {
if (depth == len) {
res.add(new ArrayList<>(path));
return;
}
for (int i = 0; i < len; i++) {
if (!used[i]) {
path.addLast(nums[i]);
used[i] = true;
System.out.println(" 递归之前 => " + path);
dfs(nums, len, depth + 1, path, used, res);
used[i] = false;
path.removeLast();
System.out.println("递归之后 => " + path);
}
}
}
public static void main(String[] args) {
int[] nums = {1, 2, 3};
Solution solution = new Solution();
List<List<Integer>> lists = solution.permute(nums);
System.out.println(lists);
}
}
递归之前 => [1]
递归之前 => [1, 2]
递归之前 => [1, 2, 3]
递归之后 => [1, 2]
递归之后 => [1]
递归之前 => [1, 3]
递归之前 => [1, 3, 2]
递归之后 => [1, 3]
递归之后 => [1]
递归之后 => []
递归之前 => [2]
递归之前 => [2, 1]
递归之前 => [2, 1, 3]
递归之后 => [2, 1]
递归之后 => [2]
递归之前 => [2, 3]
递归之前 => [2, 3, 1]
递归之后 => [2, 3]
递归之后 => [2]
递归之后 => []
递归之前 => [3]
递归之前 => [3, 1]
递归之前 => [3, 1, 2]
递归之后 => [3, 1]
递归之后 => [3]
递归之前 => [3, 2]
递归之前 => [3, 2, 1]
递归之后 => [3, 2]
递归之后 => [3]
递归之后 => []
输出 => [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]
不会debug的小白自己硬写出来的步骤:
在理解了回溯算法后我自己尝试写了一次代码:
//用来存放所有的全排列组合
List<List<Integer>> permute=new ArrayList<>();
List<Integer> temp = new ArrayList<>();
public List<List<Integer>> permute(int[] nums) {
//用来记载某一数字是否已经存在在这个组合里,默认都为false;
boolean [] exist=new boolean [nums.length];
if(nums.length==0){
return permute;
}
for(int i=0;i<nums.length;i++) exist[i]=false;
backtracking(nums,0,exist);
return(permute);
}
public void backtracking(int []nums,int index, boolean [] exist){
if(index==nums.length){
permute.add(new ArrayList<>(temp));//保存结果
return;
}
for(int i=0;i<nums.length;i++){
//找不存在的数添加到组合中
if(!exist[i]) {
temp.add(nums[i]);
exist[i] = true;
backtracking(nums, index + 1,exist);
//开始回溯
exist[i] = false;
temp.remove(temp.size()-1);
}
}
注意点:
第一遍我写的时候,这里写的是permute.add(temp);但是发现提交后怎么结果全是空集,我一直以为是自己的list列表删除操作有问题,后来这位老哥解释了我看了下,感觉还是不太理解,但是以后遇到这种情况,我至少知道了该怎么处理。
解释:
因为 Java 和 Python 参数传递的时候,传的是地址,全程只有一个 path 变量在变长变短。 res . add ( path )每一次把path所在的内存地址复制到 res 中。深度优先遍历完成以后 path 为空,所以 res 中全部的元素都为空。
C++版代码:
class Solution {
public:
vector<vector<int>>ans;
vector<int> temp;
vector<bool>st;
vector<vector<int>> permute(vector<int>& nums) {
temp=vector<int>(nums.size());
st=vector<bool>(nums.size());
dfs(nums,0);
return ans;
}
void dfs(vector<int>&nums ,int u){
if(u==nums.size()){
ans.push_back(temp);
return ;
}
for(int i=0;i<nums.size();i++){
if(!st[i]){
temp[u]=nums[i];
st[i]=true;
dfs(nums,u+1);
temp[u]=0;
st[i]=false;
}
}
}
};