# using backtracking def dbackspace(s, t) -> bool: picked = [] n = len(s) def f(i) -> bool: if i >= n: return "".join(map(lambda j: s[j], picked)) == t picked.append(i) if f(i+1): return True if picked: picked.pop() if picked: picked.pop() return f(i+1) return f(0) # using recursion+memoization from functools import lru_cache def dbackspace(s, t) -> bool: @lru_cache() def f(i,j) -> bool: if i >= len(s) and j >= len(t): return True elif i >= len(s) or j >= len(t): return False if s[i] == t[j] and f(i+1,j+1): return True return f(i+1, max(0, j-1)) return f(0,0) # bottom-up dynamic programming def dbackspace(s,t) -> bool: m,n = len(s), len(t) dp = [[False for _ in range(n+1)] for _ in range(m+1)] dp[-1][-1] = True for i in range(m-1, -1, -1): for j in range(n): if s[i] == t[j] and dp[i+1][j+1]: dp[i][j] = True dp[i][j] |= dp[i+1][max(0, j-1)] return dp[0][0] # move right to left, much easier: inspired by AlphaCode output # https://deepmind.com/blog/article/Competitive-programming-with-AlphaCode def dbackspace(s,t) -> bool: m,n = len(s), len(t) i,j = m-1, n-1 while i >= 0 and j >= 0: if s[i] == t[j]: i -= 1 j -= 1 elif i >= 2: i -= 2 else: i -= 1 return j < 0 assert dbackspace("", "") == True assert dbackspace("ababa", "ba") == True assert dbackspace("ababa", "bb") == False assert dbackspace("aaa", "aaaa") == False assert dbackspace("aababa", "ababa") == True