We are given S, a length n string of characters from the set {'D', 'I'}. (These letters stand for "decreasing" and "increasing".)
A valid permutation is a permutation P[0], P[1], ..., P[n] of integers {0, 1, ..., n}, such that for all i:

If S[i] == 'D', then P[i] > P[i+1], and;
If S[i] == 'I', then P[i] < P[i+1].

How many valid permutations are there?  Since the answer may be large, return your answer modulo 10^9 + 7.
 
Example 1:
Input: "DID"
Output: 5
Explanation: 
The 5 valid permutations of (0, 1, 2, 3) are:
(1, 0, 3, 2)
(2, 0, 3, 1)
(2, 1, 3, 0)
(3, 0, 2, 1)
(3, 1, 2, 0)

 
Note:

1 <= S.length <= 200
S consists only of characters from the set {'D', 'I'}.

Difficulty: MEDIUM
Tags: Dynamic programming
Skill types: Dynamic programming

Starter code:
class Solution:
    def numPermsDISequence(self, S: str) -> int:
        

Solutions:
class Solution:

	def numPermsDISequence(self, S):
		dp = [1] * (len(S) + 1)
		for (a, b) in zip('I' + S, S):
			dp = list(itertools.accumulate(dp[:-1] if a == b else dp[-1:0:-1]))
		return dp[0] % (10 ** 9 + 7)


class Solution:

	def numPermsDISequence(self, S: str) -> int:
		n = len(S) + 1
		dp = [[0] * (n + 1) for _ in range(n + 1)]
		dp[1][0] = 1
		MOD = 10 ** 9 + 7
		for i in range(2, n + 1):
			p = [0] + list(itertools.accumulate(dp[i - 1]))
			for j in range(i):
				(L, R) = (None, None)
				if S[i - 2] == 'D':
					L = j
					R = i - 2
				else:
					L = 0
					R = j - 1
				dp[i][j] = (p[R + 1] - p[L]) % MOD
				dp[i][j] %= MOD
		return sum(dp[n]) % MOD


from functools import lru_cache

class Solution:

	def numPermsDISequence(self, S):
		MOD = 10 ** 9 + 7
		N = len(S)

		@lru_cache(None)
		def dp(i, j):
			if not 0 <= j <= i:
				return 0
			if i == 0:
				return 1
			elif S[i - 1] == 'D':
				return (dp(i - 1, j) + dp(i, j + 1)) % MOD
			else:
				return (dp(i - 1, j - 1) + dp(i, j - 1)) % MOD
		return sum((dp(N, j) for j in range(N + 1))) % MOD


class Solution:

	def numPermsDISequence(self, S: str) -> int:
		MOD = 10 ** 9 + 7
		N = len(S)
		dp = [[0] * (N + 1) for _ in range(N + 1)]

		def solve(i, j):
			if not 0 <= j <= i:
				return 0
			if dp[i][j]:
				return dp[i][j]
			if i == 0:
				return 1
			if S[i - 1] == 'D':
				dp[i][j] = (solve(i, j - 1) + solve(i - 1, j - 1)) % MOD
			else:
				dp[i][j] = (solve(i, j + 1) + solve(i - 1, j)) % MOD
			return dp[i][j]
		return sum((solve(N, j) for j in range(N + 1))) % MOD


from functools import lru_cache

class Solution:

	def numPermsDISequence(self, S: str) -> int:
		MOD = 10 ** 9 + 7

		@lru_cache(None)
		def presum(n, last):
			if last == 0:
				return 0
			return DP(n, last - 1) + presum(n, last - 1)

		@lru_cache(None)
		def DP(n, last):
			if n == 0:
				return 1
			if S[n - 1] == 'D':
				return (presum(n - 1, n) - presum(n - 1, last)) % MOD
			else:
				return presum(n - 1, last) % MOD
		return sum((DP(len(S), i) for i in range(len(S) + 1))) % MOD


from functools import lru_cache

class Solution:

	def numPermsDISequence(self, S: str) -> int:
		MOD = 10 ** 9 + 7

		@lru_cache(None)
		def presum(n, last):
			if last == 0:
				return 0
			return DP(n, last - 1) + presum(n, last - 1)

		@lru_cache(None)
		def DP(n, last):
			if n == 0:
				return 1
			if S[n - 1] == 'D':
				return (presum(n - 1, n) - presum(n - 1, last)) % MOD
			else:
				return presum(n - 1, last) % MOD
		return presum(len(S), len(S) + 1) % MOD


class Solution:

	def numPermsDISequence(self, S: str) -> int:
		MOD = 10 ** 9 + 7
		n = len(S)

		@lru_cache(None)
		def dp(i, j):
			if not 0 <= j <= i:
				return 0
			if i == 0:
				return 1
			elif S[i - 1] == 'D':
				return (dp(i, j + 1) + dp(i - 1, j)) % MOD
			else:
				return (dp(i, j - 1) + dp(i - 1, j - 1)) % MOD
		return sum((dp(n, j) for j in range(n + 1))) % MOD


class Solution:

	def numPermsDISequence(self, S: str) -> int:
		d = [0] * (len(S) + 1)
		d[0] = 1
		for (i, c) in enumerate(S):
			if c == 'D':
				for j in range(i - 1, -1, -1):
					d[j] += d[j + 1]
			else:
				for j in range(1, i + 1):
					d[j] += d[j - 1]
				for j in range(i + 1, 0, -1):
					d[j] = d[j - 1]
				d[0] = 0
		return sum(d) % 1000000007


class Solution:

	def numPermsDISequence(self, S: str) -> int:
		M = pow(10, 9) + 7
		N = len(S)
		S = '#' + S
		dp = [[0] * (N + 1) for _ in range(N + 1)]
		dp[0][0] = 1
		for i in range(1, N + 1):
			for j in range(i + 1):
				if S[i] == 'D':
					for k in range(j, i + 1):
						dp[i][j] += dp[i - 1][k]
				else:
					for k in range(0, j):
						dp[i][j] += dp[i - 1][k]
		res = 0
		for i in range(N + 1):
			res += dp[N][i]
		return res % M


class Solution:

	def numPermsDISequence(self, s: str) -> int:
		n = len(s)
		dp = [[0 for i in range(n + 1)] for i in range(n + 1)]
		dp[0][0] = 1
		for i in range(1, n + 1):
			for j in range(i + 1):
				if s[i - 1] == 'D':
					for k in range(j, i):
						dp[i][j] += dp[i - 1][k]
				else:
					for k in range(j):
						dp[i][j] += dp[i - 1][k]
		return sum(dp[n][:]) % (pow(10, 9) + 7)


class Solution:

	def numPermsDISequence(self, S: str) -> int:
		n = len(S)
		if n <= 1:
			return 1
		dp = [[0 for _ in range(n + 1)] for _ in range(n + 1)]
		dp[0][0] = 1
		for (idx, s) in enumerate(S):
			for end in range(idx + 2):
				if s == 'D':
					for i in range(end, idx + 2):
						dp[idx + 1][end] += dp[idx][i]
				else:
					for i in range(end):
						dp[idx + 1][end] += dp[idx][i]
		return sum(dp[-1]) % (10 ** 9 + 7)


from functools import lru_cache

class Solution:

	def numPermsDISequence(self, S: str) -> int:
		mod = 10 ** 9 + 7
		n = len(S)

		@lru_cache(None)
		def dfs(i, j):
			if i == 0:
				return 1
			elif S[i - 1] == 'D':
				return sum((dfs(i - 1, k) for k in range(j, i))) % mod
			else:
				return sum((dfs(i - 1, k) for k in range(j))) % mod
		return sum((dfs(n, j) for j in range(n + 1))) % mod


class Solution:

	def numPermsDISequence(self, S: str) -> int:
		n = len(S)
		mod = 10 ** 9 + 7
		solns = [[0] * (n + 2) for _ in range(n + 2)]
		solns[0][0] = 1
		for i in range(1, n + 1):
			for j in range(i + 1):
				k = i - j
				if S[-i] == 'D':
					for r in range(0, k):
						solns[j][k] += solns[j + r][k - r - 1]
				else:
					for r in range(0, j):
						solns[j][k] += solns[j - r - 1][k + r]
				solns[j][k] %= mod
		result = sum((solns[i][n - i] for i in range(n + 1)))
		return result % mod