题意分析
- 首先,题目给出一个大小为n的数组,然后,需要我们求出这个数组的全排列。但是要注意的是这个数组里面可能存在相同的数字。
思路分析
解法一 库函数实现
- 学习过C++的同学应该都直到,C++有一个库函数next_permutation可以用来处理数组的全排列问题,但是这个库函数需要我们先对这个数组进行升序排序。具体我们来看一下源码。
template<class _BidIt> inline
bool _Next_permutation(_BidIt _First, _BidIt _Last)
{ // permute and test for pure ascending, using operator<
//-----------------------------------------------\
_DEBUG_RANGE(_First, _Last);
_BidIt _Next = _Last;
if (_First == _Last || _First == --_Next)
return (false);
//检查边界
//-----------------------------------------------/
// 我们看到,这里写了一个空循环
for (; ; )
{ // find rightmost element smaller than successor
_BidIt _Next1 = _Next;
if (_DEBUG_LT(*--_Next, *_Next1))
{ // swap with rightmost element that's smaller, flip suffix
_BidIt _Mid = _Last;
for (; !_DEBUG_LT(*_Next, *--_Mid); )
;
std::iter_swap(_Next, _Mid);
//从右往左找到相邻的两个,右边比左边大,左边那个就是需要被替换的,然后从右边找到一个比这个元素大的,交换这两个元素的位置
std::reverse(_Next1, _Last);
// 交换之后,翻转交换元素的后面的所有元素
return (true);
}
if (_Next == _First)
{ // pure descending, flip all
std::reverse(_First, _Last);
return (false);
}
}
}- 具体请看代码
- 需要进行全排列,根据数学中排列组合的知识,全排列的时间复杂度为O(n!)
- 除了参数和结果数组基本没有使用其余变量,空间复杂度为O(1)
class Solution {
public:
vector<vector<int> > permuteUnique(vector<int> &num) {
vector<vector<int> > ans;
sort(num.begin(),num.end()); // 注意,全排列需要先对数组进行升序排列
do{
ans.push_back(num);
// 利用C++的库函数进行遍历所有的排列
}while(next_permutation(num.begin(), num.end()));
return ans;
}
};- 最后说一句,如果是为了学习算法,还是不要偷懒,最好还是自己可以实现这个功能,不然注定只是一名调库工程师。所以我们下面来为大家介绍如何利用DFS的回溯解决这个问题。
解法二 回溯法
- 首先,我默认大家都已经了解了深度优先搜索的基础知识。如果有不了解的,请看这个传送门.
- 然后,我给大家回一个图帮助大家更好地理解什么是回溯?
其实就类似于我们日常的撤回功能,我们在进行某一种行为的时候这个状态改变了,但是我们发现这个行为是错误的,我们就需要进行撤回操作,恢复执行这个行为之前的状态。当然,真正的回溯其实远不是如此,这个只是帮助大家理解。
好了,我们接下来说一下DFS操作,递归参数为遍历到的数字,递归出口为数字到了num数组的大小,然后就是遍历数组,我们需要对没有被遍历到的数字执行递归操作,递归前需要将这个位置标记为访问了,同时存入,递归出来后需要将这个位置重新标记为未访问,然后之前存入的数字弹出。最后记得给得到的序列去重即可。
代码如下
- 全排列的时间复杂度未O(n!)
- 使用了unordered_map和一些中间的vector进行处理,空间复杂度为O(n)
class Solution {
public:
unordered_map<int,bool> mp;
vector<vector<int> > ans;
vector<int> tmp,now;
int len;
void dfs(int cnt){ // cnt表示当前遍历到的数字的个数
if(cnt==len+1){ // 递归出口
ans.push_back(now);
return;
}
for(int i=0;i<len;i++){
if(mp[i]==0){
// 如果这个数字没有被访问,先将这个数字放到数组里面
now.push_back(tmp[i]);
mp[i]=1; // 然后进行标记
dfs(cnt+1);
mp[i]=0; // 进行回溯
now.pop_back();
}
}
}
vector<vector<int> > permuteUnique(vector<int> &num) {
tmp=num;
len=num.size();
dfs(1);
// 可能存在重复的数字,所以需要进行去重处理
vector<vector<int> > res;
sort(ans.begin(),ans.end());
int m=unique(ans.begin(),ans.end())-ans.begin();
for(int i=0;i<m;i++){
res.push_back(ans[i]);
}
return res;
}
};
京公网安备 11010502036488号