这是获取字符串的所有排列的经典问题的变体。
你的教授希望你做出的归纳是这个问题很适合使用递归的解决方案。
字符串排列的基本算法s
如下:
- 选择 中的第一项
s
。
- 获取其他项目的所有排列
s
(选定的项目除外)。
- 将所选项目添加到步骤 2 中的每个排列。
- 对 的下一个字符重复
s
。
这是使用函数式 Java库的有效解决方案。
导入这些...
import fj.F;
import fj.P2;
import fj.P1;
import fj.data.Stream;
import static fj.data.Stream.nil;
import static fj.data.Stream.cons;
import static fj.data.Stream.range;
import static fj.data.Enumerator.charEnumerator;
import static fj.data.Show.streamShow;
import static fj.data.Show.charShow;
import static fj.P2.map2_;
查找排列的递归函数:
public Stream<Stream<Character>> permutations(final Stream<Character> s) {
return selections(s).bind(
new F<P2<Character, Stream<Character>>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>>()
f(final P2<Character, Stream<Character>> ys) {
return permutations(ys._2()).bind(cons(ys._1()));
}
});
}
依次选择每个元素的递归函数:
public Stream<P2<Character, Stream<Character>>>
selections(final Stream<Character> s) {
if (xs.isEmpty())
return nil();
else {
final char x = xs.head();
final Stream<Character> xs = s.tail()._1();
return cons(P.p(x, xs),
new P1<Stream<P2<Character, Stream<Character>>>>() {
public Stream<P2<Character, Stream<Character>>> _1() {
return selections(xs).map(map2_().f(cons(x))));
}
});
}
}
然后,获取字符 '0' 到 '9' 的所有排列:
Show<Stream<Character>> s = streamShow(charShow);
for (Stream<Character> ps : permutations(range(charEnumerator, '0', '9'))) {
System.out.println(s.showS(ps));
}
编辑:这实际上是comonads的一个很好的用例。使用最新的函数式 Java 主干头,您可以使用 Zipper comonad 执行此操作,如下所示:
public static Stream<Stream<Character>> perms(Stream<Character> s) {
Stream<Stream<Character>> r = single(Stream.<Character>nil());
for (final Zipper<Character> z : fromStream(s))
r = join(z.cobind(
new F<Zipper<Character>, Stream<Stream<Character>>>() {
public Stream<Stream<Character>> f(final Zipper<Character> zp) {
return perms(zp.lefts().reverse().append(zp.rights())).map(compose(
Stream.<Character>cons().f(zp.focus()),
P.<Stream<Character>>p1()));
}
}).toStream());
return r;
}