leetcode 47 全排列II
目录
一、问题描述
二、解题思路
整体思路
具体思路
三、代码实现
解法一:剪除不合法的分支
解法二:只进入合法的分支
一、问题描述
二、解题思路
整体思路
画出本题的决策树,决策树与leetcode 46 全排列-CSDN博客一致,在其基础上需要考虑重复的情况,即剪枝,所以可以采用回溯+剪枝来解决这个问题;
具体思路
以示例一为例,其决策树如下:
观察画决策树的过程我们可以发现剪枝策略为:
<1>使用过的位置的数不能再使用(used数组来记录使用情况);
<2>同一个节点的所有分支中,相同的元素只能选择一次;
(1)函数功能:dfs函数用于寻找start位置开始所以的排列;
(2)递归出口:如果path的长度等于nums的长度,表示此时的排列为全排列,将path加入ret;
(3)函数体:
1)解法一,当当前节点已被使用,或者当前节点不是第一个元素且不是第一次出现在这一层(不合法分支),则continue。处理当前位置,再dfs处理后续位置,最后回溯恢复现场;
2)解法二,当当前节点未被使用,且当前位置为0号位置,或者当前位置为第一次再这一层出现(合法分支),就处理当前位置,再dfs处理后续位置,最后回溯恢复现场;
三、代码实现
解法一:剪除不合法的分支
class Solution {vector<vector<int>> ret;vector<int> path; bool used[8]={false};
public:vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(),nums.end());dfs(nums,0);return ret;}void dfs(vector<int>& nums,int start){//递归出口if(path.size()==nums.size()){ret.push_back(path);return ;}for(int i=0;i!=nums.size();i++){//剪枝不合法情况if(used[i]==true||(i!=0&&nums[i-1]==nums[i]&&used[i-1]==false))continue;//处理当前节点path.push_back(nums[i]);used[i]=true;dfs(nums,i+1);//恢复现场path.pop_back();used[i]=false;}}
};
解法二:只进入合法的分支
class Solution {vector<vector<int>> ret;vector<int> path; bool used[8]={false};
public:vector<vector<int>> permuteUnique(vector<int>& nums) {sort(nums.begin(),nums.end());dfs(nums,0);return ret;}void dfs(vector<int>& nums,int start){//递归出口if(path.size()==nums.size()){ret.push_back(path);return ;}for(int i=0;i!=nums.size();i++){//只进入合法的分支if(used[i]==false&&(i==0||nums[i-1]!=nums[i]||(nums[i-1]==nums[i])&&used[i-1]==true)){//处理当前节点path.push_back(nums[i]);used[i]=true;dfs(nums,i+1);//恢复现场path.pop_back();used[i]=false;}}}
};