1、题目:面试题 08.07. 无重复字符串的排列组合
无重复字符串的排列组合。编写一种方法,计算某字符串的所有排列组合,字符串每个字符均不相同。
示例1:
输入:S = "qwe"
输出:["qwe", "qew", "wqe", "weq", "ewq", "eqw"]
示例2:
输入:S = "ab"
输出:["ab", "ba"]
2、思路
这是一道经典的回溯算法题,我们可以遍历排列的每个位置,每个位置就将字符填进去一遍,同时用一个数组标识字符串中每个位置的字符是否被用过,如果被用过了,这个字符就不能再填入这个位置。
3、代码
-
操作字符串(效率低)
class Solution {
private List<String> res;
private String S;
private boolean[] flag;
public String[] permutation(String S) {
this.S = S;
this.res = new ArrayList<>();
this.flag = new boolean[S.length()];
dfs("");
return res.toArray(new String[0]);
}
private void dfs(String s) {
if (s.length() == S.length()) {
res.add(s);
return;
}
for (int i = 0; i < S.length(); i++) {
if (!flag[i]) {
flag[i] = true;
dfs(s + S.charAt(i));
flag[i] = false;
}
}
}
}
提交记录:
-
操作字符数组(优化,效率高)
我们将字符串转换成字符数组,字符串底层也是字符数组,但是每一个新的字符串都会创建新的字符数组,所以不仅浪费空间,也浪费时间;而转换成字符数组之后,我们就只需要对这个数组进行操作,不用扩容之类的,就能很节约资源和性能。
我们遍历整个数组,将当前下标的字符和之后下标的字符两两交换,每次当前下标之前的位置都是排好的,不会担心之后的字符会出现用过的,所以进一步优化代码,省略掉标识数组。
class Solution {
private List<String> res = new ArrayList<>();
public String[] permutation(String S) {
char[] cs = S.toCharArray();
dfs(cs, 0);
return res.toArray(new String[0]);
}
private void dfs(char[] cs, int index) {
if (index == cs.length - 1) {
res.add(new String(cs));
return;
}
for (int i = index; i < cs.length; i++) {
swap(cs, index, i);
dfs(cs, index + 1);
swap(cs, index, i);
}
}
/**
* 交换数组中的两个元素
*/
private void swap(char[] cs, int i, int j) {
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
}
提交记录: