目录
- 1、题目
- 2、思考
- 3、优化
1、题目
给定一个 没有重复 数字的序列,返回其所有可能的全排列。
2、思考
老规矩,先画出给出的例子的解空间树:
观察我们可以发现:
1、深度向下一层深入时,出现过的元素不能再出现,我们能选择的只有没有选择过的元素,此处我用的哈希法set。
2、结束条件是:同一个树枝上的结点个数>=nums数组的size().
于是可以得到初步代码:注意这里判断元素是否出现过我用的set,后面会有优化
class Solution {
public:vector<vector<int>> result;vector<int> res;unordered_set<int> set;void backtracking(vector<int>& nums){//如果res元素个数和nums一样多说明一个排列已经完成if(res.size() == nums.size()){result.push_back(res);return;}for(int i=0;i<nums.size();i++){//如果这个元素在剩下的元素中,处理结点if(set.find(nums[i])!=set.end()){//处理结点;set.erase(nums[i]);res.push_back(nums[i]);//递归,探索下一层backtracking(nums); //递归//回溯,撤销处理结果res.pop_back();set.insert(nums[i]);}//如果这个元素已经用过了,不做处理}return;}vector<vector<int>> permute(vector<int>& nums) {result.clear();res.clear();//装载setfor(int i=0;i<nums.size();i++) set.insert(nums[i]);//开始回溯backtracking(nums);return result;}
};
很明显因为频繁使用了set的插入操作,删减操作。我的时间效率并不高。
接下来优化一下。
3、优化
这里判断是否出现的内容其实就是nums数组的元素。所以我们可以创建一个used数组,对应这个nums数组。
used[i]一开始为false,如果在res中压入了nums[i],那么我们就说明这个数用过了。这时使used[i]=true;
再次遍历的时候,如果used[i]=true;就跳过,说明这个数已经用过了。
下面是优化代码;
class Solution {
public:vector<vector<int>> result;vector<int> res;vector<bool> used;void backtracking(vector<int>& nums){//如果res元素个数和nums一样多说明一个排列已经完成if(res.size() == nums.size()){result.push_back(res);return;}for(int i=0;i<nums.size();i++){//如果这个元素在剩下的元素中,处理结点if(used[i] == false){//处理结点;used[i]=true;res.push_back(nums[i]);//递归,探索下一层backtracking(nums); //递归//回溯,撤销处理结果res.pop_back();used[i]=false;}//如果这个元素已经用过了,不做处理}return;}vector<vector<int>> permute(vector<int>& nums) {result.clear();res.clear();//装载used数组for(int i=0;i<nums.size();i++) used.push_back(false);backtracking(nums);return result;}
};
对比速度:
有很明显的速度提升。