输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
示例:
输入:s = “abc”
输出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]
来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/zi-fu-chuan-de-pai-lie-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
思路:
这应该是剑指offer这本书上的思路,把全排列问题转化成“遍历字符串,并替换两个字符”。
关键点是去重。
如果不去重的话,
如"abscajoaka"第一个’a’作pivot时,欲固定位置0上的字符,pivot可以和它之后的任意字符chs[i](包含它本身)做替换生成新的字符串,在此基础上分析位置1处的字符’b’为pivot时的情况(欲固定位置1上的字符)。
去重交给notSame方法实现:
如果pivot到chs[i]之间存在和chs[i]相同的字符,那么跳过这个chs[i],表示chs[i]已经登录过pivot所在位置了。
比如上面的"abscajoaka",pivot='b’时,chs[7]=‘a’,由于他们之间存在和chs[7]相同的字符chs[4],那么chs[4]必然在chs[7]与pivot发生交换之前与pivot交换,所以chs[7]与pivot会产生重复的分支,于是剪枝去重。
a b s c a j o a k a // chs
0 1 2 3 4 5 6 7 8 9 // i
public String[] permutation(String s) {
ArrayList<String> res = new ArrayList<>();
char[] chs = s.toCharArray();
f(chs,0,res);// the 2nd argument means the index of pivot
return res.toArray(new String[0]);
}
public void f(char[] chs,int index, ArrayList<String> res){
if(index==chs.length){
String temp = new String(chs);
res.add(temp);
return;
}
for(int i=index;i<chs.length;i++){
if(notSame(chs,index,i)){ // 去重
swap(chs,i, index);
f(chs,index+1,res);
swap(chs,i,index);
}
}
}
public void swap(char[] chs, int i,int j){
char ch = chs[i];
chs[i]=chs[j];
chs[j]=ch;
}
public boolean notSame(char[] chs, int start, int end){// 注意,精妙之处在于当start==end时,return false, 这样也会收录 “位置index上依然是字符chs[index]” 的答案,比如 “abcd”, when index=0, we wil have subAnswers like "acbd","adcb",... and so on, which means chs[0] still is allowed to stay at 0.
for(int i=start;i<end;i++){
if(chs[i]==chs[end]){
return false;
}
}
return true;
}