题目来源:https://leetcode-cn.com/problems/permutations/
题目描述
- 给定一个 没有重复 数字的序列,返回其所有可能的全排列。
示例:
输入: [1,2,3]
输出:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
题目大意
- 算是比较经典的回溯法的问题,返回所有可能的全排列,对于全排列问题,可以使用回溯法解决(在数据量不大的情况下,因为回溯法时间复杂度一般较高),思路可以参考【如下比较详细的题解】
https://leetcode-cn.com/problems/permutations/solution/hui-su-suan-fa-python-dai-ma-java-dai-ma-by-liweiw/
回溯法
- 经典dp问题,为了以防排列中出现重复的元素,可以使用bool辅助记录那个元素是否已经在当前排列中,如果对具体递归流程不明白,可以打印排列内容加深理解【注释部分】
- 注意下图前几行此处的2和3都移除出排列,但1没移除,是因为移除2后,此时i=1,所以还需要走当前递归栈的for循环,也就是下一个元素nums[2]=3入排列中,后续的流程类似
-
class Solution {
public:
vector<vector<int>> ret;
vector<int> ans;
vector<bool> used;
int n;
vector<vector<int>> permute(vector<int>& nums) {
n = nums.size();
used.assign(n, false);
dfs(nums, 0);
return ret;
}
void dfs(vector<int>&nums, int depth){
if(depth == n){
ret.push_back(ans);
return;
}
for(int j = 0; j < n ; ++j){
if(!used[j]){
ans.push_back(nums[j]);
used[j] = true;
//cout << "递归之前=> " << "\t" << depth << "\t";
//for (auto num : ans) {
// cout << num << ",";
//}
dfs(nums, depth + 1);
used[j] = false;
ans.pop_back();
//cout << "递归之后=> " << "\t" << depth << "\t";
//for (auto num : ans) {
// cout << num << ",";
//}
//cout << endl;
}
}
}
};
复杂度分析
- 时间复杂度:O(n*n!)。可知回溯的时间复杂度还是很大的,优化的话通常有【剪枝法】,确定了第一个元素后,后续所有元素循环次数依次递减,也就是n!(n的阶乘),需要用O(n)的时间复制到答案数据中,也就是O(n*n!)
- 空间复杂度:O(n)。因为将所有用到的数据设为全局变量,此处只需要O(n)的递归栈空间就行