目录
- 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();
//装载set
for(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;
}
};
对比速度:
有很明显的速度提升。