为了分析卸载用户公共行为,发现初级的解法并不能满足时间复杂度。

动态规划求解矩阵:

def dp_loopkup(lx, ly, lookup):
    for i in range(1, lx + 1):
        for j in range(1, ly + 1):
            if X[i - 1] == Y[j - 1]:
                lookup[i][j] = lookup[i - 1][j - 1] + 1
            else:
                lookup[i][j] = max(lookup[i - 1][j], lookup[i][j - 1])

初级递归解法:


def findLCS(X, Y):
    lx = len(X)
    ly = len(Y)
    lookup = [[0 for x in range(ly + 1)] for y in range(lx + 1)]
    dp_loopkup(lx, ly, lookup)

    def LCS(m, n):
        if m == 0 or n == 0:
            return {()}
        if X[m - 1] == Y[n - 1]:
            lcs = LCS(m - 1, n - 1)
            return {(*l, X[m - 1]) for l in lcs}
        if lookup[m - 1][n] > lookup[m][n - 1]:
            return LCS(m - 1, n)
        if lookup[m][n - 1] > lookup[m - 1][n]:
            return LCS(m, n - 1)
        top = LCS(m - 1, n, )
        left = LCS(m, n - 1)
        return top.union(left)

    r = LCS(lx, ly)
    return r

发现不对劲,长度大一点,算不出来。简单分析一下,加一个缓存。(常规操作)

def findLCS(X, Y):
    lx = len(X)
    ly = len(Y)
    lookup = [[0 for x in range(ly + 1)] for y in range(lx + 1)]
    dp_loopkup(lx, ly, lookup)

    @lru_cache()
    def LCS(m, n):
        if m == 0 or n == 0:
            return {()}
        if X[m - 1] == Y[n - 1]:
            lcs = LCS(m - 1, n - 1)
            return {(*l, X[m - 1]) for l in lcs}
        if lookup[m - 1][n] > lookup[m][n - 1]:
            return LCS(m - 1, n)
        if lookup[m][n - 1] > lookup[m - 1][n]:
            return LCS(m, n - 1)
        top = LCS(m - 1, n, )
        left = LCS(m, n - 1)
        return top.union(left)

    r = LCS(lx, ly)
    return r

长度再一大发现: RecursionError: maximum recursion depth exceeded in comparison

不想动 python 只好转迭代。转迭代通用的技巧就是使用栈。

但具体问题怎么求解,其实并不是那么直观。反复试错得到:


def findLCS_iter(X, Y):
    lx = len(X)
    ly = len(Y)
    lookup = [[0 for x in range(ly + 1)] for y in range(lx + 1)]
    dp_loopkup(lx, ly, lookup)

    def LCS(lm, ln):
        range_queue = deque()
        result = set()
        range_queue.append((lm, ln, ()))
        while len(range_queue) > 0:

            m, n, common = range_queue.pop()
            if m == 0 or n == 0:
                result.add(common)
                continue
            if X[m - 1] == Y[n - 1]:
                range_queue.append((m - 1, n - 1, (X[m - 1], *common)))
                continue
            if lookup[m - 1][n] > lookup[m][n - 1]:
                range_queue.append((m - 1, n, common))
                continue
            if lookup[m][n - 1] > lookup[m - 1][n]:
                range_queue.append((m, n - 1, common))
                continue

            range_queue.append((m - 1, n, common))
            range_queue.append((m, n - 1, common))

        return result

    return LCS(lx, ly)

到这一步其实已经满足需求了至少可以求解了。

还是发现有点慢。只好再做一次 cache 了。

def findLCS_iter(X, Y):
    lx = len(X)
    ly = len(Y)
    lookup = [[0 for x in range(ly + 1)] for y in range(lx + 1)]
    dp_loopkup(lx, ly, lookup)

    class RememberDeque(deque):
        def __init__(self):
            self.rember = set()
            super().__init__()

        def append(self, x):
            if x not in self.rember:
                self.rember.add(x)
                super().append(x)

    def LCS(lm, ln):
        range_queue = RememberDeque()
        result = set()
        range_queue.append((lm, ln, ()))
        while len(range_queue) > 0:
            m, n, common = range_queue.pop()

            if m == 0 or n == 0:
                result.add(common)
                continue
            if X[m - 1] == Y[n - 1]:
                range_queue.append((m - 1, n - 1, (X[m - 1], *common)))
                continue
            if lookup[m - 1][n] > lookup[m][n - 1]:
                range_queue.append((m - 1, n, common))
                continue
            if lookup[m][n - 1] > lookup[m - 1][n]:
                range_queue.append((m, n - 1, common))
                continue

            range_queue.append((m - 1, n, common))
            range_queue.append((m, n - 1, common))

        return result

 

到此为止,我的认知上就只能这样了。

是否还有更好的方案呢?

更好的数据结构?

deque 和 cache 结合?

或者是其他什么约束条件,某些元组不用放入栈里?

 

jiamo post at 2021-10-27