按唯一模式分割字符串

时间:2016-05-16 22:52:52

标签: python string algorithm split pattern-matching

我无法在以下方面找到合适的答案:

假设我有以下返回的LONG int(或任何字符串):

longnr = 26731623516244147357200698985770699644500911065919594945175038371437093557337774208653

我可以通过以下方式轻松拆分:

splitnr = [26731,62351,624,41,4735,720,0698,9857,7069,964,450,091,10659,195,94,94517,5038,3714,3709,35,573,37,7,74208653]

每种组合都是独一无二的,因此没有重复的数字。 我在简单的代码中执行此操作,只需迭代每个项目并将它们添加到字符串中,直到找到重复的数字。然后只需将此字符串写入列表,空字符串,添加刚检查过的数字,然后继续,直到完成所有操作。

我想要的是尽可能少的组合。 因此,首先尝试找到所有10个数字的唯一组合,然后查找剩下的9个,8,7等等。

我需要正则表达式吗? 我无法完成这项工作,有些人建议我需要大量的模式。

下一个选项:

len(set(str(longnr)[0:10])) == len(str(longnr)[0:10])

这适用于前10个检查它是否唯一。

如何以最佳方式离开这里? 订单必须像splitnr一样保留。

2 个答案:

答案 0 :(得分:1)

我确信爱德华彼得斯得到了答案。但从经验上看,似乎所有三种解决方案都同样出色:

from random import choice

def edward_peters(string):
    sequences = [[]]
    for end in range(1, len(string) + 1):
        def candidate_sequences():
            for previous_end in range(max(0, end - 10), end):
                substring = string[previous_end:end]
                if len(substring) == len(set(substring)):
                    yield sequences[previous_end] + [substring]

        sequences.append(min(candidate_sequences(), key=len))
    return sequences[-1]

def brendan_abel(long_string):
    if not long_string:
        return []
    cur_i = None
    cur_s = None
    max_i = None
    max_s = None
    for i, s in enumerate(long_string):
        if cur_s is None or s in cur_s:
            if cur_s and (max_s is None or len(cur_s) > len(max_s)):
                max_i = cur_i
                max_s = cur_s
            cur_i = i
            cur_s = [s]
        else:
            cur_s.append(s)
    else:
        if cur_s and (max_s is None or len(cur_s) > len(max_s)):
            max_i = cur_i
            max_s = cur_s
    before = long_string[:max_i]
    after = long_string[max_i + len(max_s):]
    return brendan_abel(before) + [''.join(max_s)] + brendan_abel(after)

def ruud(string):
    result = []
    current = ''
    for c in string:
        if c in current:
            result.append(current)
            current = c
        else:
            current += c
    result.append(current)
    return result

def main():
    while True:
        string = ''.join(choice('1234567890') for _ in range(10000))
        results = [func(string) for func in [edward_peters, brendan_abel, ruud]]
        assert all(''.join(result) == string for result in results)
        assert len(set(map(len, results))) == 1

main()

我根本无法直观地理解这一点。似乎Brendan Abel对Edward Peters'解决方案是OP倒退,例如

print edward_peters(string)
['49', '9', '3849', '3089', '91', '1', '15', '58', '42876', '81926', '6720', '90', '0', '27103', '3064', '436', '6', '862', '2', '201', '7091', '912', '23', '6345', '582', '382', '2', '82457', '64937', '0574', '2743', '983', '4382']

答案 1 :(得分:0)

你可以使用递归函数来做到这一点,它会像分而治之的排序算法一样工作。最糟糕的情况是O(n^2)(好吧,它基本上总是O(n^2)

  1. 浏览原始列表中的每个元素并尝试制作最长的唯一链,存储最大链的起始索引(我们可以在这里作弊,因为我们知道10是绝对最大值,仅使用数字和我们一找到10长的链就停止了,但我在下面的例子中没有这样做。)

  2. 将列表拆分为2个单独的列表,一个列在我们刚找到的元素列表之前,另一个列在之后,并将它们都输入到递归函数中。

  3. 重新组合结果

  4. 下面的函数假设你传递了一个字符串,所以首先将你的长号字符串化,然后将字符串转换回数字。

    def func(long_string):
        if not long_string:
            return []
        cur_i = None
        cur_s = None
        max_i = None
        max_s = None
        for i, s in enumerate(long_string):
            if cur_s is None or s in cur_s:
                if cur_s and (max_s is None or len(cur_s) > len(max_s)):
                    max_i = cur_i
                    max_s = cur_s
                cur_i = i
                cur_s = [s]
            else:
                cur_s.append(s)
        else:
            if cur_s and (max_s is None or len(cur_s) > len(max_s)):
                max_i = cur_i
                max_s = cur_s
        before = long_string[:max_i]
        after = long_string[max_i + len(max_s):]
        return func(before) + [''.join(max_s)] + func(after)
    

    long_number = 1233423732174096361032409234987352
    list_of_strings = func(str(long_number).strip('L'))  # strip L for older python versions.
    list_of_numbers = map(int, list_of_strings)