我遇到了THIS帖子,其中非常努力地解释了打印所有字符串的递归解决方案。
public class Main {
private static void permutation(String prefix, String str){
int n = str.length();
if (n == 0)
System.out.println(prefix);
else {
for (int i = 0; i < n; i++)
permutation(prefix + str.charAt(i),
str.substring(0, i) + str.substring(i+1));
}
}
public static void main(String[] args) {
permutation("", "ABCD");
}
}
但是当我们开始弹出堆栈时,我仍然无法获得该部分。例如,递归一直持续到置换(“ABCD”,“”),其中基本情况遇到并且它打印ABCD。但现在发生了什么?我们从函数调用堆栈中弹出置换(“ABC”,“D”)..我们用这个做什么等等。
请有人帮忙解释一下。
另外,我需要一些关于时间复杂度的指针?不像完整的计算,但有一些提示。
答案 0 :(得分:2)
更简单的示例:permutation("", "ABC")
,将空字符串表示为*
:
* ABC + A BC + AB C - ABC *
| |
| ` AC B - ACB *
|
+ B AC + BA C - BAC *
| |
| ` BC A - BCA *
|
` C AB + CA B - CAB *
|
` CB A - CBA *
请注意,这看起来就像一棵树。实际上,它叫一棵树。当我们开始时,我们将进入("A", "BC")
州;我们继续致电("AB", "C")
,最后致电("ABC", "")
。在这里我们打印输出。然后我们记得我们有未完成的业务,我们返回循环,但上一级的循环只有一个循环。所以我们也在那里完成,并返回("A", "BC")
级别; "BC"
中有两个元素,我们只完成了"B"
,所以它现在"C"
转:我们称之为("AC", "B")
},然后调用("ACB", "")
。现在("A", "BC")
下的所有循环都已完成......但是等等,仍然可以做!因为("", "ABC")
还有两个要处理的字母。因此,我们通常称之为&#34;深度优先搜索&#34;分支机构。
在每个级别都是一个循环。循环收缩(我们在左侧的粗分支中迭代3次,然后在下一级中迭代2次,然后只有一次)但仍然存在循环。总的来说,我们进行n * (n - 1) * (n - 2) * ... * 2 * 1
次迭代。 O(N!)
?
答案 1 :(得分:1)
作为一种递归,您可以使用 Stream.reduce
方法。首先为每个字符位置准备一个可能的字符组合的列表,然后连续减少这些列表的流为一个列表,通过对列表元素对求和。
作为列表元素,您可以使用 Map<Integer,String>
,其中 key - 字符在字符串中的位置,value - 字符本身,以及总结这些映射的内容,不包括那些已经存在的键。
然后你会得到一个字符排列列表。
比如你有一个四字串????
,那么你要经过三步约化,连续累加结果:
str1 + str2 = sum1 | sum1 + str3 = sum2 | sum2 + str4 = 总和 |
---|---|---|
? + ? = ?? |
?? + ? = ??? |
??? + ? = ???? |
15
字符的 4
和是 60
和,导致 4! = 24
排列。
// original string
String str = "????";
// array of characters of the string
int[] codePoints = str.codePoints().toArray();
// contents of the array
System.out.println(Arrays.toString(codePoints));
//[120276, 120277, 120278, 120279]
// list of permutations of characters
List<Map<Integer, String>> permutations = IntStream.range(0, codePoints.length)
// Stream<List<Map<Integer,String>>>
.mapToObj(i -> IntStream.range(0, codePoints.length)
// represent each character as Map<Integer,String>
.mapToObj(j -> Map.of(j, Character.toString(codePoints[j])))
// collect a list of maps
.collect(Collectors.toList()))
// intermediate output
//[{0=?}, {1=?}, {2=?}, {3=?}]
//[{0=?}, {1=?}, {2=?}, {3=?}]
//[{0=?}, {1=?}, {2=?}, {3=?}]
//[{0=?}, {1=?}, {2=?}, {3=?}]
.peek(System.out::println)
// reduce a stream of lists to a single list
.reduce((list1, list2) -> list1.stream()
// summation of pairs of maps from two lists
.flatMap(map1 -> list2.stream()
// filter out those keys that are already present
.filter(map2 -> map2.keySet().stream()
.noneMatch(map1::containsKey))
// join entries of two maps
.map(map2 -> new LinkedHashMap<Integer, String>() {{
putAll(map1);
putAll(map2);
}}))
// collect into a single list
.collect(Collectors.toList()))
// List<Map<Integer,String>>
.orElse(List.of(Map.of(0, str)));
// number of permutations
System.out.println(permutations.size()); // 24
// number of rows (factorial of string length - 1)
int rows = IntStream.range(1, codePoints.length)
.reduce((a, b) -> a * b).orElse(1);
// column-wise output
IntStream.range(0, rows)
.mapToObj(i -> IntStream.range(0, permutations.size())
.filter(j -> j % rows == i)
.mapToObj(permutations::get)
.map(map -> map.toString().replace(" ", ""))
.collect(Collectors.joining(" ")))
.forEach(System.out::println);
//{0=?,1=?,2=?,3=?} {1=?,0=?,2=?,3=?} {2=?,0=?,1=?,3=?} {3=?,0=?,1=?,2=?}
//{0=?,1=?,3=?,2=?} {1=?,0=?,3=?,2=?} {2=?,0=?,3=?,1=?} {3=?,0=?,2=?,1=?}
//{0=?,2=?,1=?,3=?} {1=?,2=?,0=?,3=?} {2=?,1=?,0=?,3=?} {3=?,1=?,0=?,2=?}
//{0=?,2=?,3=?,1=?} {1=?,2=?,3=?,0=?} {2=?,1=?,3=?,0=?} {3=?,1=?,2=?,0=?}
//{0=?,3=?,1=?,2=?} {1=?,3=?,0=?,2=?} {2=?,3=?,0=?,1=?} {3=?,2=?,0=?,1=?}
//{0=?,3=?,2=?,1=?} {1=?,3=?,2=?,0=?} {2=?,3=?,1=?,0=?} {3=?,2=?,1=?,0=?}
另见:How do you check if a word has an anagram that is a palindrome?
答案 2 :(得分:1)
您可以使用 map
和 reduce
方法生成字符串的排列数组。
此解决方案假设原始字符串不包含重复字符,否则应使用置换映射 Map<Integer,String>
而不是置换数组 {{1 }}。
String[]
方法采用一对置换数组,并将它们的元素成对求和,累积结果。例如,对于一个五字符的字符串 reduce
的四步归约:
?????
0 [?, ?, ?, ?, ?]
1 [?, ?, ?, ?, ?]
---
sum1: [??, ??, ??, ??, ...]
2 [?, ?, ?, ?, ?]
---
sum2: [???, ???, ???, ...]
3 [?, ?, ?, ?, ?]
---
sum3: [????, ????, ...]
4 [?, ?, ?, ?, ?]
---
total: [?????, ?????, ...]
// original string
String str = "?????";
// array of characters of the string
int[] codePoints = str.codePoints().toArray();
String[] permutations = IntStream.range(0, codePoints.length)
// intermediate output, character-position
.peek(i -> System.out.print(i + " "))
// prepare an array of possible permutations for each character-position
.mapToObj(i -> Arrays.stream(codePoints).mapToObj(Character::toString)
// array of characters as strings
.toArray(String[]::new))
// intermediate output, array of possible permutations
.peek(arr -> System.out.println(Arrays.deepToString(arr)))
// reduce a stream of arrays to a single array
.reduce((arr1, arr2) -> Arrays.stream(arr1)
// summation of pairs of strings from two arrays
.flatMap(str1 -> Arrays.stream(arr2)
// filter out those characters that are already present
.filter(str2 -> !str1.contains(str2))
// concatenate two strings
.map(str2 -> str1 + str2))
// collect into a single array
.toArray(String[]::new))
// otherwise an empty array
.orElse(new String[0]);
中间输出,每个字符位置的可能排列数组:
// final output
System.out.println("Number of permutations: " + permutations.length);
// number of rows
int rows = permutations.length / 10;
// permutations by columns
IntStream.range(0, rows).forEach(i -> System.out.println(
IntStream.range(0, permutations.length)
.filter(j -> j % rows == i)
.mapToObj(j -> permutations[j])
.collect(Collectors.joining(" "))));
最终输出,按列排列:
0 [?, ?, ?, ?, ?]
1 [?, ?, ?, ?, ?]
2 [?, ?, ?, ?, ?]
3 [?, ?, ?, ?, ?]
4 [?, ?, ?, ?, ?]