题目描述
给定一个可包含重复数字的序列,返回所有不重复的全排列。
解题思路
如果该序列不包含可重复数字,属于基本的深度搜索问题。
定义一个数组表示序列中数字是否已选。对于深度搜索的每一层,尝试将序列中未选择数字选择,递归下去即可。
这里简单写一下代码:
vector<vector<int>> res; // 定义最终结果
vector<int> path; // 定义一次选择路径
vector<bool> visited; // 定义序列数字是否已选
vector<vector<int>> permute(vector<int>& nums) {
visited = vector<bool>(nums.size(),false); // 根据nums大小定义选择数组visited
dfs(nums,0);
return res;
}
void dfs(vector<int>& nums,int index)
{
if(index == nums.size()) // 表明选择完成
{
res.push_back(path);
return ;
}
for(int i = 0;i < nums.size();i++)
{
if(!visited[i]) // 如果该位未曾被选择,尝试选择该位
{
visited[i] = true;
path.push_back(nums[i]);
dfs(nums,index + 1);
path.pop_back(); // 该句和下一句用于还原场景
visited[i] = false;
}
}
}
现在题目要求序列数字可重复,那么如何定义选择方式才能做到不重复搜索呢?
对于相同的数字,保持其相对顺序不变,这样得到的是不重复的全排列。
通过代码实现这一原则,有两种不同的思路 (都需先将序列进行排序):
- 第一种
本实现和 “不包含可重复数字的序列” 实现方式相同 —— 每次向 path 末尾添加已选择元素。
相同数字中,如果前面的数字没有被选择,则后面的数字一定不会被选择。举例如下:当前未选择数字序列为 “2,2,3,4”,在该趟搜索中,第二个 2 一定不会作为选择对象。vector<vector<int>> res; // 定义最终结果 vector<int> path; // 定义一次选择路径 vector<bool> visited; // 定义序列数字是否已选 vector<vector<int>> permuteUnique(vector<int>& nums) { visited = vector<bool>(nums.size(),false); sort(nums.begin(),nums.end()); // 需对序列进行排序 dfs(nums,0); return res; } void dfs(vector<int>& nums,int index) { if(index == nums.size()) { res.push_back(path); return ; } for(int i = 0;i < nums.size();i++) { if(!visited[i]) { // 这里是剪枝条件 if(i > 0 && nums[i] == nums[i - 1] && !visited[i - 1]) continue; visited[i] = true; path.push_back(nums[i]); dfs(nums,index + 1); path.pop_back(); visited[i] = false; } } }
- 第二种
这种方法和上面做法有点不同,是依次将数放置在未选择的路径位置中,而上面的做法是将未选择的数依次放置在已选择路径的末尾。
这种方法每次将 nums[index] 放置在 path 中未选择位置中。如果 n u m s [ i n d e x + 1 ] = = n u m s [ i n d e x ] nums[index + 1] == nums[index] nums[index+1]==nums[index] ,那么下一个元素只能放置在当前元素所在位置之后,反之可从 0 位置开始放置。vector<vector<int>> res; // 定义最终结果 vector<int> path; // 定义一次选择路径 vector<bool> visited; // 定义路径中某位是否已选择 // 这一步千万要注意 vector<vector<int>> permuteUnique(vector<int>& nums) { visited = vector<bool>(nums.size(),false); path = vector<int>(nums.size()); sort(nums.begin(),nums.end()); // 需对序列进行排序 dfs(nums,0,0); return res; } void dfs(vector<int> &nums,int index,int start) { if(index == nums.size()) { res.push_back(path); return ; } for(int i = start;i < path.size();i++) { if(!visited[i]) { path[i] = nums[index]; visited[i] = true; if(index + 1 < nums.size() && nums[index + 1] == nums[index]) // 如果下一位和当前位相同,则选择路径位置受限 dfs(nums,index + 1,i + 1); else dfs(nums,index + 1,0); visited[i] = false; } } }