【问题标题】:Explore all sub-sequence探索所有子序列
【发布时间】:2018-12-29 04:50:10
【问题描述】:

我已经尝试了几天来解决这个问题,但没有任何成功。

关于这个问题:

给定一个序列“2 2 4 4”。

我们从序列中连续取 2 个数字,例如:2 2 ,2 4, 4 4。

如果 2 个数字的和是一个可被 2 整除的数字,我们将这 2 个数字替换并放入 2 个数字的结果,例如:(2+2 = 4, 4/2 = 2) 所以新序列是(2 4 4),但在这里我应该找到所有可能的序列。 如果不可能找到可被 2 整除的偶数,则返回序列。

图片应该是怎样的

红色矩形是我无法得到的序列:(

我的代码:

def recFunc(n):
    for i in range(len(n)):
        if i+1 <= len(n)-1: #control out of range
            if ((n[i] + n[i+1]) % 2 == 0):
                newnum = int((n[i] + n[i+1])/2)
                n[i:i+2] = [newnum]
                return recFunc(n)
            else:
                if i+1 == len(n)-1:
                    return [n]
                else:
                    continue
def main(s):
    s = s.split()
    integers = [int(x) for x in s]
    final = recFunc(integers)
    print(final)

main('2 2 4 4')

我在这里所做的是,将序列转换为整数,将它们发送到一个新函数。我应该递归地接收所有序列。

我对序列进行了迭代,并通过 n[i] 和第二个 n[i+1] 获取第一个数字(并控制我是否可以让第二个数字不超出范围)。

最后的结果应该按照size序列的递增方式排序,如果2个序列的长度相同,那么我们按照序列的第一个数字排序。

最后我应该收到['3', '2 3', '3 4', '2 3 4']

【问题讨论】:

    标签: python python-3.x recursion


    【解决方案1】:

    我创建了几个函数来实现这个目标:

    1. least_check 给出一个True/False 关于序列是否是“最小”的(例如'2 4' 将返回False,而'3 4' 将返回True
    2. find_leasts 这是递归函数,它将序列分解到问题所示树中的下一个级别(例如,'2 2 4 4' 将分解为 '2 4 4''2 3 4''2 2 4')直到它到达所有“最少”
    3. mainfind_leasts 函数中创建所有“最少”yielded 的列表,并删除所有重复项(例如,示例序列有两次 '3')并返回唯一“最少”列表

    答案:

    def least_check(n):
        check_list = [int(x) for x in n.split(' ')]
        for a, b in zip(check_list[:-1], check_list[1:]):
            if (a + b) % 2 == 0:
                return False
        return True
    
    def find_leasts(n):
        if len(n.split(' ')) == 1:
            yield n
        for i in range(len(n.split(' '))-1):
            s = [int(x) for x in n.split(' ')]
            if (s[i] + s[i+1]) % 2 == 0:
                s[i] = int((s[i] + s[i+1]) / 2)
                s.pop(i+1)
            sub_n = ' '.join(str(j) for j in s)
            if least_check(sub_n):
                yield sub_n
            else:
                yield from find_leasts(sub_n)
    
    def main(s):
        all_leasts = [x for x in find_leasts(s)]
        unique_leasts = list(set(all_leasts))
        return unique_leasts
    
    seq = '2 2 4 4'
    print(sorted(main(seq), key=len))
    

    结果:

    ['3', '2 3', '3 4', '2 3 4']
    

    更新:

    上述解决方案有很多split()s和' '.join()s,以避免递归函数修改列表引用(列表名称是指向其内存地址的指针-如果需要,请参阅this site以获得进一步解释) 从当前范围以外的深度。

    当查看在'30 20 10 30 6 6' 序列上收到的错误并考虑到通过sys.setrecursionlimit 使用最大递归是not recommended 时,我重新评估了递归是否甚至是必要的——并确定它不是。

    以下是迭代解决方案中使用的函数:

    1. least_check - 与原始答案相同
    2. break_down - 获取一个列表并将其分解为树中下一层的所有列表(例如,'2 2 4 4' 将分解为 '2 4 4''2 3 4''2 2 4'
    3. least_lister - 遍历可能最少的列表队列,直到 least_lists 中的所有列表都是最少的
    4. main - 执行所有 split()' '.join() 操作并在返回结果之前删除重复项

    迭代解决方案:

    def least_check(check_list):
        for a, b in zip(check_list[:-1], check_list[1:]):
            if (a + b) % 2 == 0:
                return False
        return True
    
    def break_down(s, ret):
        for i in range(len(s)-1):
            if (s[i] + s[i+1]) % 2 == 0:
                bd_list = s.copy()
                bd_list[i] = int((bd_list[i] + bd_list[i+1]) / 2)
                bd_list.pop(i+1)
                ret.append(bd_list)
    
    def least_lister(n):
        least_lists = []
        if least_check(n):
            least_lists.append(n)
        else:
            i = 0
            break_down(n, least_lists)
            while i < len(least_lists):
                if least_check(least_lists[i]):
                    i+=1
                else:
                    break_down(least_lists[i], least_lists)
                    least_lists.pop(i)
        return least_lists
    
    def main(s):
        s_list = [int(x) for x in s.split(' ')]
        all_leasts = least_lister(s_list)
        unique_leasts = list(set([' '.join(str(j) for j in i) for i in all_leasts]))
        return unique_leasts
    
    seq = '30 20 10 30 6 6'
    print(sorted(main(seq), key=len))
    

    迭代结果:

    ['18', '19', '19 6', '25 6', '25 10', '25 14', '30 13', '30 15', '30 17', '30 13 6', '30 17 6', '30 15 12', '30 15 18']
    

    列表参考示例

    def add_to_list(n):
        n.append(len(n))
        print(n)
    
    a = [0, 1]
    
    add_to_list(a)
    print(a)
    

    列表参考示例输出:

    [0, 1, 2]
    [0, 1, 2]
    

    【讨论】:

    • 非常感谢您的回复,它通过函数yield节省了内存空间,但是字符串和int之间有很多转换,所以如果我放一个更长的字符串“seq = '30 20 10 30 6 6'" 它转到 RecursionError: 在获取对象的 str 时超出最大递归深度
    • @LordNord 我的回复太长,无法发表评论,请查看我的回复更新。
    • 感谢您的回复,即使响应太长,您的代码也可以完美运行,问题是我应该递归解决它,当我尝试使用 return 而不是 yield 时,我不知道为什么,但它只解决了树的左侧(就像图片,我的意思是这棵树),即使我递归地做它也不会去红色矩形(在图片中),你有有什么解决办法吗?
    • @LordNord 您的递归仅在左侧向下的原因是因为列表名称指的是内存地址。我添加到答案中的列表参考示例证明了这种效果。 This site 深入解释为什么会这样,questions like this 进入可能的解决方法。问题是,即使你实现了一个,就像我在原始答案中所做的那样,你最终会得到与我在执行 '30 20 10 30 6 6' 序列时相同的 maxrecursion 错误。
    【解决方案2】:

    以下是我的递归解决方案,基于您的图表,它可以处理“30 20 10 30 6 6”而不会出现堆栈问题。数据转换、排序和冗余减少由main() 例程处理。 sub_sequence() 函数接受一个数组并返回一个与图表逻辑匹配的数组数组:

    def sub_sequence(array):
        solutions = []
    
        length = len(array)
        changed = False
    
        if length > 1:
            for index in range(len(array) - 1):
                prefix, pair, postfix = array[:index], array[index:index + 2], array[index + 2:]
    
                total = sum(pair)
    
                if total % 2 == 0:
                    solutions.extend(sub_sequence([*prefix, total // 2, *postfix]))
                    changed = True
    
        if length < 2 or not changed:
            solutions.append(array)
    
        return solutions
    
    def main(string):
        unsorted_redundant_sub_sequences = sub_sequence([int(number) for number in string.split()])
        unsorted_non_redundant_strings = set(" ".join(map(str, sequence)) for sequence in unsorted_redundant_sub_sequences)
        sorted_non_redundant_strings = sorted(unsorted_non_redundant_strings, key=lambda x: (len(x), x))
        print(sorted_non_redundant_strings)
    
    main('30 20 10 30 6 6')
    

    输出

    > python3 test.py
    ['18', '19', '19 6', '25 6', '25 10', '25 14', '30 13', '30 15', '30 17', '30 13 6', '30 17 6', '30 15 12', '30 15 18']
    > 
    

    【讨论】:

      【解决方案3】:

      让我们一步一步看这个问题。

      第一: 将数组的第一个数字与第二个数字相加,

      结果除以二,

      用新值创建一个新数组,

      如果是的话

      然后在新的数组上调用递归

      否则将新数组放入静态数据结构中

      第二: 首先我们需要查看所有的索引,

      将所有内容放入一个循环中,从索引 I = 0 开始到长度为 2

      第三: 处理静态数组,根据需要对其进行排序并打印结果。

      我不擅长python,但我希望这个伪代码对你有帮助。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-09-20
        • 1970-01-01
        • 1970-01-01
        • 2019-05-18
        • 1970-01-01
        • 2017-09-13
        • 2020-03-31
        相关资源
        最近更新 更多