<p>对于许多字符串,当前算法将给出不正确的结果。</p>
<p>我怀疑有更有效的方法来解决这个问题,但这里有一个暴力的解决方案。它生成输入字符串的子集,按长度降序排列。子集中的元素保留原始字符串的顺序。一旦<code>count_deletions</code>找到一个有序的子集,它就会返回它(转换回字符串),以及删除的次数。因此,它找到的解决方案保证不短于任何其他输入字符串排序选择。</p>
<p>请参阅<a href="https://docs.python.org/3/library/itertools.html" rel="nofollow noreferrer">^{<cd2>} docs</a>了解我使用的各种<code>itertools</code>函数的信息;生成子集的算法是从<a href="https://docs.python.org/3/library/itertools.html#itertools-recipes" rel="nofollow noreferrer">Recipes</a>部分中的<code>powerset</code>示例派生出来的。</p>
<pre><code>from itertools import chain, combinations
def count_deletions(s):
for t in chain.from_iterable(combinations(s, r) for r in range(len(s), 0, -1)):
t = list(t)
if t == sorted(t):
return ''.join(t), len(s) - len(t)
# Some test data.
data = [
"abcdefg",
"cba",
"abcb",
"vwzyx",
"zvwzyx",
"adabcef",
"fantastic",
]
for s in data:
print(s, count_deletions(s))
</code></pre>
<p><strong>输出</strong></p>
^{pr2}$
<p>这个数据集不足以完全测试为解决这个问题而设计的算法,但我想这是一个不错的起点。:)</p>
<p/><hr/>
<strong>更新</strong>
<p>这是一个python3实现的算法,由萨尔瓦多Dali在链接页面上提到。它比我以前的暴力方法快得多,特别是对于较长的字符串。</p>
<p>我们可以通过对字符串的副本进行排序,然后找到原始字符串的最长公共子序列(LCS)和排序后的字符串来找到排序最长的子序列。Salvador的版本从排序的字符串中删除了重复的元素,因为他希望结果严格递增,但这里不需要这样做。</p>
<p>这段代码只返回所需的删除次数,但是很容易修改它以返回实际排序的字符串。</p>
<p>为了使这个递归函数更有效,它使用了functools中的<a href="https://docs.python.org/3/library/functools.html#functools.lru_cache" rel="nofollow noreferrer">^{<cd5>}</a>修饰符。</p>
^{3}$
<p><strong>输出</strong></p>
<pre><code>abcdefg 0
cba 2
abcb 1
vwzyx 2
zvwzyx 3
adabcef 1
fantastic 5
</code></pre>