【递归/动规】 | 求所有非递减子序列 CS61A 2023Spring Lab10

68 阅读1分钟

题目链接

def insert_into_all(item, nested_list):
    """Return a new list consisting of all the lists in nested_list,
    but with item added to the front of each. You can assume that
     nested_list is a list of lists.

    >>> nl = [[], [1, 2], [3]]
    >>> insert_into_all(0, nl)
    [[0], [0, 1, 2], [0, 3]]
    """
    return [[item] + l for l in nested_list]


def subseqs(s):
    """Return a nested list (a list of lists) of all subsequences of S.
    The subsequences can appear in any order. You can assume S is a list.

    >>> seqs = subseqs([1, 2, 3])
    >>> sorted(seqs)
    [[], [1], [1, 2], [1, 2, 3], [1, 3], [2], [2, 3], [3]]
    >>> subseqs([])
    [[]]
    """
    if not s:
        return [[]]
    else:
        rest = subseqs(s[1:])
        return rest + insert_into_all(s[0], rest)

def non_decrease_subseqs(s):
    """Assuming that S is a list, return a nested list of all subsequences
    of S (a list of lists) for which the elements of the subsequence
    are strictly nondecreasing. The subsequences can appear in any order.

    >>> seqs = non_decrease_subseqs([1, 3, 2])
    >>> sorted(seqs)
    [[], [1], [1, 2], [1, 3], [2], [3]]
    >>> non_decrease_subseqs([])
    [[]]
    >>> seqs2 = non_decrease_subseqs([1, 1, 2])
    >>> sorted(seqs2)
    [[], [1], [1], [1, 1], [1, 1, 2], [1, 2], [1, 2], [2]]
    """
    def subseq_helper(s, prev):
        if not s:
            return [[]]
        elif s[0] < prev:
            return subseq_helper(s[1:], prev)
        else:
            a = subseq_helper(s[1:], s[0])
            b = subseq_helper(s[1:], prev)
            return insert_into_all(s[0], a) + b
    return subseq_helper(s, -1)

subseq_helper函数使用递归的方式来生成非递减子序列。它的基本思路是:

  • 如果s为空序列,那么返回一个包含空列表的列表,表示已经找到了一个非递减子序列。
  • 如果s的第一个元素小于prev,说明无法将当前元素加入到非递减子序列中,所以递归调用subseq_helper函数,将s的第一个元素舍弃,继续处理剩余的序列s[1:]。
  • 如果s的第一个元素大于等于prev,那么有两种情况:
    • 将s的第一个元素加入到非递减子序列中,递归调用subseq_helper函数处理剩余的序列s[1:],并将结果存储在变量a中。
    • 不将s的第一个元素加入到非递减子序列中,直接递归调用subseq_helper函数处理剩余的序列s[1:],并将结果存储在变量b中。
  • 最后,通过调用insert_into_all函数将s的第一个元素插入到a中的每个非递减子序列中,然后将结果与b合并,并返回最终的结果。

总结:

  • helper 返回的是 s 的所有非递减子序列,满足所有子序列的s[0]>=prev
  • base case 是 s 为空,直接返回 [[]]
  • 接下来两种情况:
    1. 如果s[0] > prev,返回helper(s[1:], prev),依然保证了s[1:]的所有非递减子序列第一个元素<=prev;
    2. s[0] >= prev,可以返回 helper(s[1:], prev),还可以返回 helper(s[1:], s[0]) 的每一个元素前面加上 s[0],因为进来的时候已经保证了s[0]>=prev,最后结果是这两类非递减子序列相加

helper核心目标就是要得到第一个元素大于等于prev的非递减子序列,然后就可以把s[0]加到前面去