我试图编写代码来创建给定单词的所有字谜的惰性流。我最初使用这段代码:
public static Stream<WordSequence> anagram(Stream<WordSequence> data, Object[] parameters) {
return data.unordered().flatMap(WordSequence.forEachWord(Functions::allAnagrams)).distinct();
}
private static Stream<Word> allAnagrams(Word data) {
if (data.length() <= 1)
return Stream.of(data);
Stream<Word> ret = Stream.empty();
for (int i = 0; i < data.length(); i++) {
char ch = data.charAt(i);
String rest = new StringBuilder(data).deleteCharAt(i).toString();
ret = Stream.concat(ret, allAnagrams(new Word(rest)).map(word -> new Word(ch + word.toString()))).unordered();
}
return ret;
}
(我使用自己的WordSequence
和Word
课程。)
我意识到这不是很有效,因为它只是连接一堆空元素和单元素流,并且它还会在返回它们的流之前计算所有字符串。我在Core Java中找到了这个很棒的算法:
StringBuilder b = new StringBuilder(word);
for (int i = b.length() - 1; i > 0; i--)
if (b.charAt(i - 1) < b.charAt(i)) {
int j = b.length() - 1;
while (b.charAt(i - 1) > b.charAt(j))
j--;
swap(b, i - 1, j);
reverse(b, i);
return new Word(b.toString());
}
return new Word(b.reverse().toString());
如果你用一个单词调用它,它将返回单词的所有字符序列中的下一个单词。
我按如下方式实施:
public static Stream<WordSequence> anagram(Stream<WordSequence> data, Object[] parameters) {
class AnagramIterator implements Iterator<Word> {
private final Word start;
private Word current;
private boolean done;
AnagramIterator(Word start) {
current = this.start = start;
}
@Override
public boolean hasNext() {
return !done;
}
@Override
public Word next() {
if (done)
throw new NoSuchElementException();
StringBuilder b = new StringBuilder(current);
for (int i = b.length() - 1; i > 0; i--)
if (b.charAt(i - 1) < b.charAt(i)) {
int j = b.length() - 1;
while (b.charAt(i - 1) > b.charAt(j))
j--;
swap(b, i - 1, j);
reverse(b, i);
current = new Word(b.toString());
done = current.equals(start);
return current;
}
current = new Word(b.reverse().toString());
done = current.equals(start);
return current;
}
private void swap(StringBuilder b, int i, int j) {
char tmp = b.charAt(i);
b.setCharAt(i, b.charAt(j));
b.setCharAt(j, tmp);
}
private void reverse(StringBuilder b, int i) {
int j = b.length() - 1;
while (i < j) {
swap(b, i, j);
i++;
j--;
}
}
}
return data.flatMap(WordSequence.forEachWord(w -> StreamSupport.stream(
Spliterators.spliteratorUnknownSize(
new AnagramIterator(w),
Spliterator.DISTINCT + Spliterator.IMMUTABLE + Spliterator.NONNULL),
false)));
}
但是,该算法存在问题。如果你给它一个单词以双字母结尾然后另一个字母,其中双字母值在数字上小于单个字母,例如&#34; ees&#34;,你得到这个字母序列:
ees
ese
ees
and that repeats infinitely
该序列不包含&#34;请参阅&#34;。
我该怎么做?
我的代码是on GitHub。
答案 0 :(得分:2)
我想到了算法正在做什么,并且有一丝洞察力。给定字符串&#34; ese&#34;,这就是算法的作用:
i
,在这种情况下指向s。j
,指向e。i - 1
和j
,交换两个e。i
开始反转字符串,交换s和e。我们希望它做的是j
指向s,这将使它交换第一个e和s。那么我们如何修改算法来实现呢?
嗯,这里找到j
:
j
指向最后一个e。i - 1
,即e,不大于j
,这是另一个e,因此j
指向最后一个e。以下是我的洞察力:改变比较大于&#34;大于&#34;到&#34;大于或等于&#34;。我改变了,它似乎有效!