题目描述
描述:输入一个长度为 n 字符串,打印出该字符串中字符的所有排列,你可以以任意顺序返回这个字符串数组。例如输入字符串ABC,则输出由字符A,B,C所能排列出来的所有字符串ABC,ACB,BAC,BCA,CBA和CAB。
数据范围:n<10。
要求:空间复杂度 O(n!),时间复杂度 O(n!)。
输入描述:输入一个字符串,长度不超过10,字符只包括大小写字母。
解题思路
字符串的排列:最直观的想法是,回溯中的全排列,只不过该全排列中的元素可能重复,故需要考虑去重。使用res表示所有结果,使用path表示当前结果,使用used表示元素是否遍历,使用backtracking表示回溯。如果path的长度等于str的长度,那么表明已经到达叶子节点,故需要将path加入到res中并返回;直接依次遍历str中的每一个元素,使用used判断当前元素是否使用过,如果使用过则继续下一轮continue,反之标记当前元素已经被使用并将其加入到当前路径中,同时继续回溯,回溯完后再弹出元素并置为未访问。由于全排列中的元素可能重复,但是结果数组要求不重复,故使用unordered_set去重,最后使用迭代器将其转换为vector<string>即可。注意,回溯类型的题目,无论是排列还是组合,都可以通过画树形图来模拟解决。以字符串"ABC"为例,先A再B再C,到C时回溯返回弹出C,然后backtracking结束回到B再弹出B,当时i=1,故继续i=2,此时C加入,然后再回溯到B,就完成ABC和ACB,其余的以此类推。
unordered_set<string> res; //结果数组
string path; //当前结果
void backtracking(vector<bool> &used,string &str)
{
//当前结果数组等于字符串长度则收集结果
if(path.size()==str.size())
{
res.emplace(path);
return;
}
//遍历字符串元素
for(int i=0;i<str.size();i++)
{
//如果已经使用过则下一轮
if(used[i]==true)
continue;
//标记使用
used[i]=true;
//加入当前路径
path.push_back(str[i]);
//继续回溯
backtracking(used, str);
//回溯结束后置为未访问以留下一次
used[i]=false;
//弹出元素
path.pop_back();
}
}
vector<string> Permutation(string str)
{
if(str.size()==0) //空字符串
return vector<string>({""});
//使用数组
vector<bool> used(str.size(),false);
backtracking(used, str);
return vector<string>(res.begin(),res.end());
}
优化:上述方法中,使用了额外的存储空间,那么能否不使用呢?当然可以!我们可以发现,上述的字符串重复,主要是由于相同元素引起的,那么我们可以通过先对字符串进行排序,然后再结合used数组和str字符串来进行去重,即树枝上的元素可以重复,但是树层上的元素不可以重复,因为如果树层上重复,那么就出现了同前面相同的排列。
vector<string> res; //结果数组
string path; //当前结果
void backtracking(vector<bool> &used,string &str)
{
//结果数组等于字符串长度则收集结果
if(path.size()==str.size())
{
res.push_back(path);
return;
}
//遍历字符串元素
for(int i=0;i<str.size();i++)
{
//树枝上可以重复树层上不可以重复 used[i-1]=false表示树层上重复 因为是回溯后的结果
if(str[i]==str[i-1]&&i>=1&&used[i-1]==false)
continue;
//如果已经使用过则下一轮
if(used[i]==true)
continue;
//标记使用
used[i]=true;
//加入当前路径
path.push_back(str[i]);
//继续回溯
backtracking(used, str);
//回溯结束后置为未访问以留下一次
used[i]=false;
//弹出元素
path.pop_back();
}
}
vector<string> Permutation(string str)
{
if(str.size()==0) //空字符串
return vector<string>({""});
//使用数组
vector<bool> used(str.size(),false);
sort(str.begin(),str.end()); //该方法一定要先排序
backtracking(used, str);
return res;
}
PS:牛客可能会给你报错,但是你自己对结果和输出即可!