0
def numDistinct(self, s: str, t: str) -> int:
    n = len(s)
    m = len(t)
    if n<m:
        return 0
    count = 0
    def check(sub, i, length):
        nonlocal count
        if i>=n:
            return 
        if length>m:
            return
        if sub!=t[:length]:
            return
        if sub==t:
            count+=1
            return
            
        for j in range(i+1,n):
            temp = sub
            sub+=s[j]
            check(sub, j, length+1)
            sub = temp
        
    for i in range(n):
        check(s[i], i, 1)
    return count

I can't find a way for memoization of this, please help. The question is to find, Given two strings s and t, return the number of distinct subsequences of s which equals t.

A string's subsequence is a new string formed from the original string by deleting some (can be none) of the characters without disturbing the remaining characters' relative positions.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
  • The easiest way to memoize in Python is to use `@functools.cache` starting with Python 39 or `functools.lrucache(None)` if you're using an earlier version. Read the documentation for details. – Frank Yellin Sep 18 '21 at 19:14
  • @FrankYellin That's not quite enough here, though. [Changes the result from 2 to 1](https://tio.run/##jVLBToQwEL3zFWM8LA2YuPFiNnbjwbM/QIhhsSxd6ZS0w8GvxynFBYwxzqV9k9c3L2/af1Jr8eGxd@PYOGugGbAmazsP2vTWEXRueKurulVJ8q4awMG8aE@aWalXXZODP4AnlwNNp4C7I2ikQwJcCBI6hakXEzQzpAg1yz2ZyAzlFA0O4X5q1HZAYn5Et/C8GAmN4IXv9Ufqh1MOOg/CZ2rFIocWO1tXXZS6tnmqPkpceKvRa1LUO5rfiGsez7@RVBwiv/wHXUrasiaDmdz/9TTUFTTWwYVjBlfhWaU62@cotpqkTM/x8bhNm3EmfXEptwaWJC/fSWZ78fMl6wXZZOMneNGLl7WPWbbQ5bShWXDOOm4l6R3/lnT9rV4tqhx2jbWnyu2mm9sJMY5f). – no comment Sep 18 '21 at 19:24
  • 3
    You want to have a memoized function, and yet it has a side effect of modifying variables. This is inconsistent. – Frank Yellin Sep 18 '21 at 19:31

1 Answers1

1

Currently your check function is run only for side-effects, whereas memoization should be used for "pure" functions that have no side-effects and are run for their return value.

Fortunately, your check function can be easily changed to a pure function, since its only side effect was to add to the count variable: rather than modify count directly, it can return the amount that count should be changed by. You can now use the functools.lru_cache or functools.cache decorator (https://docs.python.org/3/library/functools.html#functools.cache) to memoize the function.

from functools import lru_cache

def numDistinct(self, s: str, t: str) -> int:
    n = len(s)
    m = len(t)
    if n<m:
        return 0
    count = 0
    @lru_cache
    def check(sub, i, length):
        if i>=n:
            return 0
        if length>m:
            return 0
        if sub!=t[:length]:
            return 0
        if sub==t:
            return 1
        
        local_count = 0
        for j in range(i+1,n):
            temp = sub
            sub+=s[j]
            local_count += check(sub, j, length+1)
            sub = temp
        return local_count
        
    for i in range(n):
        count += check(s[i], i, 1)
    return count

print(numDistinct(None, 'foobar', 'for'))
Oli
  • 2,507
  • 1
  • 11
  • 23