题目
In this kata you have to create all permutations of an input string and remove duplicates, if present. This means, you have to shuffle all letters from the input in all possible orders. 在这个kata中,您必须创建一个输入字符串的所有排列,并删除重复项(如果存在)。这意味着,您必须以所有可能的顺序将输入中的所有字母洗牌。
例子
Permutations.singlePermutations(“a”)
shouldBe
[“a”] Permutations.singlePermutations(“ab”)shouldBe
[“ab”, “ba”] Permutations.singlePermutations(“aabb”)shouldBe
[“aabb”,”abab”,”abba”,”baab”,”baba”,”bbaa”]
分析
字符串排列组合问题,采用dfs深度优先递归遍历,将当前结果存放到cur中,直到cur长度等于s,如果最终结果result中没有cur,将cur放入result中。需要注意的是加了一个flag判断当前字符是否在本次dfs中出现过,每次遍历完一个字符后需要复位既flag置为false、cur去掉当前加上的字符。
我的解法
import java.util.*;
class Permutations {
public static List<String> singlePermutations(String s) {
return permutation(s, new boolean[s.length()], "", new ArrayList<>());
}
public static List<String> permutation(String s, boolean[] flag, String cur, List<String> result) {
if (cur.length() == s.length() && !result.contains(cur)) {
result.add(cur);
}
for (int i = 0; i < s.length(); i++) {
if (!flag[i]) {
flag[i] = true;
cur += s.charAt(i);
permutation(s, flag, cur, result);
cur = cur.substring(0, cur.length() - 1);
flag[i] = false;
}
}
return result;
}
}
参考解法
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
import java.util.List;
class Permutations {
public static List<String> singlePermutations(final String s) {
return permute("", s);
}
private static List<String> permute(final String prefix, final String s) {
return s.isEmpty()
? singletonList(prefix)
: s.chars()
.distinct()
.mapToObj(i -> (char) i)
.map(c -> permute(prefix + c, takeOut(s, c)))
.flatMap(List::stream)
.collect(toList());
}
static String takeOut(final String s, final char c) {
final int i = s.indexOf(c);
return s.substring(0, i) + s.substring(i + 1);
}
}
动态规划的解法
import java.util.*;
class Permutations {
public static List<String> singlePermutations(String s) {
// Your code here!
return permutate("",s,new ArrayList<String>());
}
public static List<String> permutate(String permute, String s, List<String> listed) {
if (s.isEmpty() && !listed.contains(permute + s)) {
listed.add(permute + s);
} else {
for (int i = 0; i < s.length(); i++) {
permutate(permute + s.charAt(i), s.substring(0,i) + s.substring(i+1,s.length()), listed);
}
}
return listed;
}
}
提升
- 解决排列组合中心思想是分治和递归
- 分治:就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。
- dfs伪代码如下
void dfs(int step)
{
判断边界
{
相应操作
}
尝试每一种可能
{
满足check条件
{
标记
继续下一步dfs(step+1)
恢复初始状态(回溯的时候要用到)
}
}
}
参考资料
回溯算法套路详解