Welcome to Subscribe On Youtube
115. Distinct Subsequences
Description
Given two strings s and t, return the number of distinct subsequences of s which equals t.
The test cases are generated so that the answer fits on a 32-bit signed integer.
Example 1:
Input: s = "rabbbit", t = "rabbit" Output: 3 Explanation: As shown below, there are 3 ways you can generate "rabbit" from s.rabbbitrabbbitrabbbit
Example 2:
Input: s = "babgbag", t = "bag" Output: 5 Explanation: As shown below, there are 5 ways you can generate "bag" from s.babgbagbabgbagbabgbagbabgbagbabgbag
Constraints:
1 <= s.length, t.length <= 1000sandtconsist of English letters.
Solutions
Solution 1: Dynamic Programming
We define $f[i][j]$ as the number of schemes where the first $i$ characters of string $s$ form the first $j$ characters of string $t$. Initially, $f[i][0]=1$ for all $i \in [0,m]$.
When $i > 0$, we consider the calculation of $f[i][j]$:
- When $s[i-1] \ne t[j-1]$, we cannot select $s[i-1]$, so $f[i][j]=f[i-1][j]$;
- Otherwise, we can select $s[i-1]$, so $f[i][j]=f[i-1][j-1]$.
Therefore, we have the following state transition equation:
\[f[i][j]=\left\{ \begin{aligned} &f[i-1][j], &s[i-1] \ne t[j-1] \\ &f[i-1][j-1]+f[i-1][j], &s[i-1]=t[j-1] \end{aligned} \right.\]The final answer is $f[m][n]$, where $m$ and $n$ are the lengths of strings $s$ and $t$ respectively.
The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$.
We notice that the calculation of $f[i][j]$ is only related to $f[i-1][..]$. Therefore, we can optimize the first dimension, reducing the space complexity to $O(n)$.
Solution 2
This implementation uses dynamic programming. It traverses the relevant values and updates its state as each value is processed. After all required states have been considered, the maintained result is returned.
-
class Solution { public int numDistinct(String s, String t) { int n = t.length(); int[] f = new int[n + 1]; f[0] = 1; for (char a : s.toCharArray()) { for (int j = n; j > 0; --j) { char b = t.charAt(j - 1); if (a == b) { f[j] += f[j - 1]; } } } return f[n]; } } // Solution 2 class Solution { public int numDistinct(String s, String t) { int n = t.length(); int[] f = new int[n + 1]; f[0] = 1; for (char a : s.toCharArray()) { for (int j = n; j > 0; --j) { char b = t.charAt(j - 1); if (a == b) { f[j] += f[j - 1]; } } } return f[n]; } } -
class Solution { public: int numDistinct(string s, string t) { int n = t.size(); unsigned long long f[n + 1]; memset(f, 0, sizeof(f)); f[0] = 1; for (char& a : s) { for (int j = n; j; --j) { char b = t[j - 1]; if (a == b) { f[j] += f[j - 1]; } } } return f[n]; } }; // Solution 2 class Solution { public: int numDistinct(string s, string t) { int n = t.size(); unsigned long long f[n + 1]; memset(f, 0, sizeof(f)); f[0] = 1; for (char& a : s) { for (int j = n; j; --j) { char b = t[j - 1]; if (a == b) { f[j] += f[j - 1]; } } } return f[n]; } }; -
class Solution: def numDistinct(self, s: str, t: str) -> int: n = len(t) f = [1] + [0] * n for a in s: for j in range(n, 0, -1): if a == t[j - 1]: f[j] += f[j - 1] return f[n] # Solution 2 class Solution: def numDistinct(self, s: str, t: str) -> int: n = len(t) f = [1] + [0] * n for a in s: for j in range(n, 0, -1): if a == t[j - 1]: f[j] += f[j - 1] return f[n] -
func numDistinct(s string, t string) int { n := len(t) f := make([]int, n+1) f[0] = 1 for _, a := range s { for j := n; j > 0; j-- { if b := t[j-1]; byte(a) == b { f[j] += f[j-1] } } } return f[n] } // Solution 2 func numDistinct(s string, t string) int { n := len(t) f := make([]int, n+1) f[0] = 1 for _, a := range s { for j := n; j > 0; j-- { if b := t[j-1]; byte(a) == b { f[j] += f[j-1] } } } return f[n] } -
function numDistinct(s: string, t: string): number { const n = t.length; const f: number[] = new Array(n + 1).fill(0); f[0] = 1; for (const a of s) { for (let j = n; j; --j) { const b = t[j - 1]; if (a === b) { f[j] += f[j - 1]; } } } return f[n]; } // Solution 2 function numDistinct(s: string, t: string): number { const n = t.length; const f: number[] = new Array(n + 1).fill(0); f[0] = 1; for (const a of s) { for (let j = n; j; --j) { const b = t[j - 1]; if (a === b) { f[j] += f[j - 1]; } } } return f[n]; } -
impl Solution { #[allow(dead_code)] pub fn num_distinct(s: String, t: String) -> i32 { let n = s.len(); let m = t.len(); let mut dp: Vec<Vec<u64>> = vec![vec![0; m + 1]; n + 1]; // Initialize the dp vector for i in 0..=n { dp[i][0] = 1; } // Begin the actual dp process for i in 1..=n { for j in 1..=m { dp[i][j] = if s.as_bytes()[i - 1] == t.as_bytes()[j - 1] { dp[i - 1][j] + dp[i - 1][j - 1] } else { dp[i - 1][j] }; } } dp[n][m] as i32 } } -
class Solution { public int numDistinct(String s, String t) { int n = t.length(); int[] f = new int[n + 1]; f[0] = 1; for (char a : s.toCharArray()) { for (int j = n; j > 0; --j) { char b = t.charAt(j - 1); if (a == b) { f[j] += f[j - 1]; } } } return f[n]; } } -
class Solution { public: int numDistinct(string s, string t) { int n = t.size(); unsigned long long f[n + 1]; memset(f, 0, sizeof(f)); f[0] = 1; for (char& a : s) { for (int j = n; j; --j) { char b = t[j - 1]; if (a == b) { f[j] += f[j - 1]; } } } return f[n]; } }; -
class Solution: def numDistinct(self, s: str, t: str) -> int: n = len(t) f = [1] + [0] * n for a in s: for j in range(n, 0, -1): if a == t[j - 1]: f[j] += f[j - 1] return f[n] -
func numDistinct(s string, t string) int { n := len(t) f := make([]int, n+1) f[0] = 1 for _, a := range s { for j := n; j > 0; j-- { if b := t[j-1]; byte(a) == b { f[j] += f[j-1] } } } return f[n] } -
function numDistinct(s: string, t: string): number { const n = t.length; const f: number[] = new Array(n + 1).fill(0); f[0] = 1; for (const a of s) { for (let j = n; j; --j) { const b = t[j - 1]; if (a === b) { f[j] += f[j - 1]; } } } return f[n]; }