Python 从给定字符串中删除多少个字符才能使其成为排序字符串

Python 从给定字符串中删除多少个字符才能使其成为排序字符串,python,string,sorting,Python,String,Sorting,我需要找到使字符串排序所需的最小删除次数 样本测试用例: # Given Input: teststr = "abcb" # Expected output: 1 # Explanation # In this test case, if I delete last 'b' from "abcb", # then the remaining string "abc" is sorted. # That is, a single deletion is required. # Given

我需要找到使字符串排序所需的最小删除次数

样本测试用例:

# Given Input:
teststr = "abcb"
# Expected output:
1

# Explanation
# In this test case, if I delete last 'b' from "abcb", 
# then the remaining string "abc" is sorted. 
# That is, a single deletion is required.

# Given Input:
teststr = "vwzyx"
# Expected output:
2

# Explanation
# Here, if I delete 'z' and 'x' from "vwzyx", 
# then the remaining string "vwy" is a sorted string.  
我尝试了以下方法,但它给出了超出时间限制的错误。 还有其他解决这个问题的方法吗

    string = input()
    prev_ord = ord(string[0])
    deletion = 0
    for char in string[1:]:
        if ord(char) > prev_ord +1 or ord(char) < prev_ord:
            deletion += 1
            continue
        prev_ord = ord(char)
    print(deletion)
string=input()
上一个ord=ord(字符串[0])
删除=0
对于字符串[1:]中的字符:
如果ord(字符)>上一个ord+1或ord(字符)<上一个ord:
删除+=1
持续
上一个ord=ord(字符)
打印(删除)

希望它适用于所有情况:)


对于许多字符串,您当前的算法将给出不正确的结果

我怀疑有更有效的方法来解决这个问题,但这里有一个蛮力解决方案。它按长度降序生成输入字符串的子集。子集中的元素保留原始字符串的顺序。只要
count\u deletions
找到一个有序子集,它就会返回它(转换回字符串)以及删除的数量。因此,它找到的解决方案保证不比输入字符串的任何其他排序选择短

有关我使用过的各种
itertools
函数的信息,请参见;生成子集的算法源自本节中的
powerset
示例

输出

abcdefg ('abcdefg', 0)
cba ('c', 2)
abcb ('abc', 1)
vwzyx ('vwz', 2)
zvwzyx ('vwz', 3)
adabcef ('aabcef', 1)
fantastic ('fntt', 5)
abcdefg 0
cba 2
abcb 1
vwzyx 2
zvwzyx 3
adabcef 1
fantastic 5
该数据集并不足以完全测试为解决此问题而设计的算法,但我想这是一个不错的起点。:)


更新

下面是Salvador Dali在链接页面上提到的算法的Python 3实现。它比我以前的蛮力方法快得多,特别是对于更长的字符串

我们可以通过排序字符串的副本,然后查找原始字符串的最长公共子序列(LCS)来查找排序后的最长子序列&排序后的字符串。Salvador的版本从排序的字符串中删除了重复的元素,因为他希望结果严格递增,但这里不需要

这段代码只返回所需的删除次数,但修改它以返回实际排序的字符串非常容易

为了使这个递归函数更有效,它使用了functools中的decorator

from functools import lru_cache

@lru_cache(maxsize=None)
def lcs_len(x, y):
    if not x or not y:
        return 0

    xhead, xtail = x[0], x[1:]
    yhead, ytail = y[0], y[1:]
    if xhead == yhead:
        return 1 + lcs_len(xtail, ytail)
    return max(lcs_len(x, ytail), lcs_len(xtail, y))

def count_deletions(s):
    lcs_len.cache_clear()
    return len(s) - lcs_len(s, ''.join(sorted(s)))

data = [
    "abcdefg",
    "cba",
    "abcb",
    "vwzyx",
    "zvwzyx",
    "adabcef",
    "fantastic",
]

for s in data:
    print(s, count_deletions(s))
输出

abcdefg ('abcdefg', 0)
cba ('c', 2)
abcb ('abc', 1)
vwzyx ('vwz', 2)
zvwzyx ('vwz', 3)
adabcef ('aabcef', 1)
fantastic ('fntt', 5)
abcdefg 0
cba 2
abcb 1
vwzyx 2
zvwzyx 3
adabcef 1
fantastic 5

不,那不行。例如,在'zvwzyx'上,它返回5,但我们可以从该字符串生成'vwz',因此删除计数仅为3。在'adabcef'上,它应该返回1,而不是4。是的,你是对的,这个问题有一个非常好的Python实现,称为上面的问题(这里)[谢谢你找到了那个复制目标@chthonicdaemon。我在我的答案中添加了一个更有效的版本。任何人都可以帮助我获得这个版本的java版本。如果可以的话,你可以帮助我获得java版本吗possible@sagar对不起,我不懂Java。但是如果你能读Python,把我的代码翻译成另一种语言应该不会太难。我建议你试试,试试看nd如果你被卡住了,在一个新问题中发布你的代码,可能会链接回这个问题,或者链接回本页顶部显示的重复目标。实际上,
@lru\u cache
似乎是python特定的库或实用工具,我在java中买不起,而且我只需要使用核心库。@sagar有一些关于在java中进行记忆的信息我用java中的LCS解决了这个问题。有一个算法对它进行了相应的修改