题目相关
题目链接
LeetCode中国,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]
]
题目分析
LeetCode 给出本题难度中等。
题意分析
根据给出序列,列出全排列。
样例数据分析
根据样例输入数据 [1,2,3] ,我去,这么简单,不就是回溯算法的经典例题吗。给出 1 ~ n 的全排列。图我就不画了。
搜索函数设计
设计搜索回溯函数可以套用套路。
1、先将函数原型写出来。比如 void dfs()。
2、根据题目要求逐一分析需要几个参数。我们用本题为例。
3、nums 这个数组肯定是要传递的。
4、既然是搜索,肯定需要位置控制。那么这个也是一个数组定义,假设名字为 vis。
5、肯定需要一个变量,表示已经搜索到了几个,假设名字为 cnt。
搜索返回条件
很清晰的知道,这个返回条件就是 cnt 的数据和 nums 数组大小一样。
第一次提交代码
class Solution {
public:
vector<vector<int> > ans;//答案
vector<vector<int>> permute(vector<int>& nums) {
vector<int> path;
//从0开始搜索,搜索到数据n,一共搜索n个数字
int n = nums.size();
vector<bool> vis(n, false);
dfs(path, vis, n, n);
return ans;
}
//参数1:path存放已经搜索出了几个数据
//参数2:vis表示
//参数3:n表示搜索的最大数据
//参数4:left还剩下几个数没有搜索到
void dfs(vector<int> &path, vector<bool> &vis, int n, int left) {
if (0==left) {
//搜索到了
ans.push_back(path);
return;
}
for (int i=1; i<=n; i++) {
if (false==vis[i]) {
vis[i]=true;
path.push_back(i);
dfs(path, vis, n, left-1);
path.pop_back();
vis[i]=false;
}
}
}
};
然后很开心地等待测试,结果如下,当头一棒。
嗯,大佬你坑我吗。竟然出现 0。于是开始改代码,不就是在数组 nums 里搞鬼,这个我会解决,大不了我先排序。这样我就知道最大值和最小值,然后从最小值到最大值搜索就就可以。
第二次提交代码
class Solution {
public:
vector<vector<int> > ans;//答案
vector<vector<int>> permute(vector<int>& nums) {
vector<int> path;
//从0开始搜索,搜索到数据n,一共搜索n个数字
int n = nums.size();
sort(nums.begin(), nums.end());//排序
vector<bool> vis(n, false);
dfs(path, nums, vis, 0);
return ans;
}
//参数1:path存放已经搜索出了几个数据
//参数2:vis表示
//参数3:开始
//参数4:结束
//参数4:cnt表示找到了几个
void dfs(vector<int> &path, vector<int>& nums, vector<bool> &vis, int cnt) {
int n=nums.size();
if (n==cnt) {
//搜索到了
ans.push_back(path);
return;
}
for (int i=nums[0]; i<=nums[n-1]; i++) {
if (false==vis[i]) {
vis[i]=true;
path.push_back(i);
dfs(path, nums, vis, cnt+1);
path.pop_back();
vis[i]=false;
}
}
}
};
然后很开心地等待测试,结果如下,懵逼了。什么情况,竟然访问到了 0x0000 地址去了,I 服了 U。
耐心仔细的读了一下输出,看了一下测试用例。我去,这个数据出得太出乎我的意料了。错误原来如下:
输入 [0, -1, 1],排序后得到 [-1, 0, 1],我的搜索代码里循环是 for (int i=nums[0]; i<=nums[n-1]; i++),也就是从 -1 到 1 的循环,而对应的 vis[i],变成了 vis[-1]、vis[0] 和 vis[1]。恭喜出现了数组越界。天啊,这也太坑了。
还是自己没有推敲清楚。所以不怕给耻笑,将整个过程贴了出来。还是老问题,数据要仔细推敲。
既然问题定位了,要解决问题就很容易。只需要修改循环起点和终点就可以了。
AC 参考代码
class Solution {
public:
vector<vector<int> > ans;//答案
vector<vector<int>> permute(vector<int>& nums) {
vector<int> path;
//从0开始搜索,搜索到数据n,一共搜索n个数字
int n = nums.size();
sort(nums.begin(), nums.end());//排序
vector<bool> vis(n, false);
dfs(path, nums, vis, 0);
return ans;
}
//参数1:path存放已经搜索出了几个数据
//参数2:nums表示给定的数据
//参数3:vis访问控制
//参数4:cnt表示找到了几个
void dfs(vector<int> &path, vector<int>& nums, vector<bool> &vis, int cnt) {
int n=nums.size();
if (n==cnt) {
//搜索到了
ans.push_back(path);
return;
}
for (int i=0; i<n; i++) {
if (false==vis[i]) {
vis[i]=true;
path.push_back(nums[i]);
dfs(path, nums, vis, cnt+1);
path.pop_back();
vis[i]=false;
}
}
}
};