Find the number of occurrences of a subsequence in a string

前端 未结 9 1606
粉色の甜心
粉色の甜心 2020-12-04 05:13

For example, let the string be the first 10 digits of pi, 3141592653, and the subsequence be 123. Note that the sequence occurs twice:



        
9条回答
  •  囚心锁ツ
    2020-12-04 05:53

    Great answer, aioobe! To complement your answer, some possible implementations in Python:

    1) straightforward, naïve solution; too slow!

    def num_subsequences(seq, sub):
        if not sub:
            return 1
        elif not seq:
            return 0
        result = num_subsequences(seq[1:], sub)
        if seq[0] == sub[0]:
            result += num_subsequences(seq[1:], sub[1:])
        return result
    

    2) top-down solution using explicit memoization

    def num_subsequences(seq, sub):
        m, n, cache = len(seq), len(sub), {}
        def count(i, j):
            if j == n:
                return 1
            elif i == m:
                return 0
            k = (i, j)
            if k not in cache:
                cache[k] = count(i+1, j) + (count(i+1, j+1) if seq[i] == sub[j] else 0)
            return cache[k]
        return count(0, 0)
    

    3) top-down solution using the lru_cache decorator (available from functools in python >= 3.2)

    from functools import lru_cache
    
    def num_subsequences(seq, sub):
        m, n = len(seq), len(sub)
        @lru_cache(maxsize=None)
        def count(i, j):
            if j == n:
                return 1
            elif i == m:
                return 0
            return count(i+1, j) + (count(i+1, j+1) if seq[i] == sub[j] else 0)
        return count(0, 0)
    

    4) bottom-up, dynamic programming solution using a lookup table

    def num_subsequences(seq, sub):
        m, n = len(seq)+1, len(sub)+1
        table = [[0]*n for i in xrange(m)]
        def count(iseq, isub):
            if not isub:
                return 1
            elif not iseq:
                return 0
            return (table[iseq-1][isub] +
                   (table[iseq-1][isub-1] if seq[m-iseq-1] == sub[n-isub-1] else 0))
        for row in xrange(m):
            for col in xrange(n):
                table[row][col] = count(row, col)
        return table[m-1][n-1]
    

    5) bottom-up, dynamic programming solution using a single array

    def num_subsequences(seq, sub):
        m, n = len(seq), len(sub)
        table = [0] * n
        for i in xrange(m):
            previous = 1
            for j in xrange(n):
                current = table[j]
                if seq[i] == sub[j]:
                    table[j] += previous
                previous = current
        return table[n-1] if n else 1
    

提交回复
热议问题