提示
LintCode中的相关算法题实现代码,可以在我的GitHub中下载。
题目需求
给定一个数字列表,返回其所有可能的排列。
样例
给出一个列表[1,2,3]
,其全排列为:
[
[1,2,3],
[1,3,2],
[2,1,3],
[2,3,1],
[3,1,2],
[3,2,1]
]
挑战
使用递归和非递归分别解决。
解题思路
这道题,主要使用的是回溯法,这里我们使用4个方法来进行回溯法的拆解。is_a_solution(int k,int n)用于判断是否符合解,void process_solution(int solution[],vector<int> &nums,vector<vector<int>> &result)主要用于处理解,void construct_candidates(int candidates[],bool position[],int n,int *ncandidates) 用于构造题解,void backtrack(int solution[],int k,int n,vector<int> &nums,bool position[],vector<vector<int>> &result)回溯方法。
主要的解题思路如下:
1.由于要求求解一个序列的全排列,那么我们需要记录那些元素是否在候选解中,我们使用一个数组来保存元素是否被选中,这里使用 position数组来保存。
2.如何判断一个组合是否为解呢?其实很简单,我们知道全排列,那么解必然是所有的元素在候选集中,这个候选集是一个解。
3.如何递归的求解呢?我们知道,一个元素一旦加入候选集,那么我们可以将对应的位置是否被选中设置为true,递归完成后,我们就将这个位置设置为false。
4.我们可以使用数组solution保存那些被选中的位置。
实现代码
class Solution {
public:
bool is_a_solution(int k,int n)
{
return n==k;
}
void process_solution(int solution[],vector<int> &nums,vector<vector<int>> &result)
{
vector<int> tmp;
for(int i=1;i<=nums.size();i++)
{
tmp.push_back(nums[solution[i]]);
}
result.push_back(tmp);
}
void construct_candidates(int candidates[],bool position[],int n,int *ncandidates)
{
for(int i=0,count=0;i<n;i++)
{
if(!position[i])
{
candidates[count++]=i;
(*ncandidates)++;
}
}
}
void backtrack(int solution[],int k,int n,vector<int> &nums,bool position[],vector<vector<int>> &result)
{
int candidates[1000];
int ncandidates=0;
if(is_a_solution(k,n))
{
process_solution(solution,nums,result);
}
else
{
k++;
construct_candidates(candidates,position,n,&ncandidates);
for (int i = 0; i <ncandidates; ++i)
{
solution[k]=candidates[i];
position[candidates[i]]=true;
backtrack(solution,k,n,nums,position,result);
position[candidates[i]]=false;
}
}
}
vector<vector<int>> permute(vector<int>& nums) {
bool position[1000];
memset(position,false,sizeof(position));
int solution[1001];
vector<vector<int>> result;
backtrack(solution,0,nums.size(),nums,position,result);
return result;
}
};