HomeLeetcode115. Distinct Subsequences - Leetcode Solutions

115. Distinct Subsequences – Leetcode Solutions

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.

Examples:

Example 1:

Input: s = "rabbbit", t = "rabbit"
Output: 3
Explanation:
As shown below, there are 3 ways you can generate "rabbit" from s.
Example 2:

Input: s = "babgbag", t = "bag"
Output: 5
Explanation:
As shown below, there are 5 ways you can generate "bag" from s.

Solution in Python:

To solve this problem, you can use dynamic programming to count the number of distinct subsequences of string s that match string t. The idea is to use a 2D array dp where dp[i][j] represents the number of distinct subsequences of s[0..i-1] that match t[0..j-1].

Python
class Solution:
    def numDistinct(self, s: str, t: str) -> int:
        # Get the lengths of the input strings
        m, n = len(s), len(t)
        
        # Create a 2D dp array initialized with 0s
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        
        # Every string (including the empty string) has exactly one subsequence equal to the empty string
        for i in range(m + 1):
            dp[i][0] = 1
        
        # Fill the dp array
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                # If the current characters in s and t match, we have two options:
                # 1. Exclude the current character of s and use the result of dp[i-1][j]
                # 2. Include the current character of s and use the result of dp[i-1][j-1]
                if s[i - 1] == t[j - 1]:
                    dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1]
                else:
                    # If the characters do not match, we only consider the result of excluding the current character of s
                    dp[i][j] = dp[i - 1][j]
        
        # The result is the value in the bottom-right corner of the dp array
        return dp[m][n]

Explanation:

  1. Initialization:
    • m and n are the lengths of strings s and t, respectively.
    • dp is a 2D list (matrix) of size (m+1) x (n+1) initialized with zeros.
    • dp[i][0] is set to 1 for all i because an empty t can always be formed by any prefix of s (including the empty prefix).
  2. Filling the DP Table:
    • Iterate through each character of s (from 1 to m) and each character of t (from 1 to n).
    • If s[i-1] == t[j-1], update dp[i][j] with the sum of dp[i-1][j] and dp[i-1][j-1]. This means you can either exclude or include the current character of s to form t[0..j-1].
    • If s[i-1] != t[j-1], update dp[i][j] with dp[i-1][j], meaning you can only exclude the current character of s.
  3. Result:
    • The value dp[m][n] represents the number of distinct subsequences of s that equal t.

This approach efficiently computes the number of distinct subsequences using dynamic programming with a time complexity of O(m * n), where m and n are the lengths of s and t, respectively.

Solution in Javascript:

JavaScript
/**
 * @param {string} s
 * @param {string} t
 * @return {number}
 */
var numDistinct = function(s, t) {
    // Get the lengths of the input strings
    const m = s.length;
    const n = t.length;
    
    // Create a 2D dp array initialized with 0s
    const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
    
    // Every string (including the empty string) has exactly one subsequence equal to the empty string
    for (let i = 0; i <= m; i++) {
        dp[i][0] = 1;
    }
    
    // Fill the dp array
    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            // If the current characters in s and t match, we have two options:
            // 1. Exclude the current character of s and use the result of dp[i-1][j]
            // 2. Include the current character of s and use the result of dp[i-1][j-1]
            if (s[i - 1] === t[j - 1]) {
                dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
            } else {
                // If the characters do not match, we only consider the result of excluding the current character of s
                dp[i][j] = dp[i - 1][j];
            }
        }
    }
    
    // The result is the value in the bottom-right corner of the dp array
    return dp[m][n];
};

Solution in Java:

Java
class Solution {
    public int numDistinct(String s, String t) {
        // Get the lengths of the input strings
        int m = s.length();
        int n = t.length();
        
        // Create a 2D dp array initialized with 0s
        int[][] dp = new int[m + 1][n + 1];
        
        // Every string (including the empty string) has exactly one subsequence equal to the empty string
        for (int i = 0; i <= m; i++) {
            dp[i][0] = 1;
        }
        
        // Fill the dp array
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // If the current characters in s and t match, we have two options:
                // 1. Exclude the current character of s and use the result of dp[i-1][j]
                // 2. Include the current character of s and use the result of dp[i-1][j-1]
                if (s.charAt(i - 1) == t.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j] + dp[i - 1][j - 1];
                } else {
                    // If the characters do not match, we only consider the result of excluding the current character of s
                    dp[i][j] = dp[i - 1][j];
                }
            }
        }
        
        // The result is the value in the bottom-right corner of the dp array
        return dp[m][n];
    }
}

Solution in C#:

C#
public class Solution {
    public int NumDistinct(string s, string t) {
        int m = s.Length;
        int n = t.Length;
        
        // Create a 2D dp array initialized with 0s
        int[,] dp = new int[m + 1, n + 1];
        
        // Every string (including the empty string) has exactly one subsequence equal to the empty string
        for (int i = 0; i <= m; i++) {
            dp[i, 0] = 1;
        }
        
        // Fill the dp array
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // If the current characters in s and t match, we have two options:
                // 1. Exclude the current character of s and use the result of dp[i-1, j]
                // 2. Include the current character of s and use the result of dp[i-1, j-1]
                if (s[i - 1] == t[j - 1]) {
                    dp[i, j] = dp[i - 1, j] + dp[i - 1, j - 1];
                } else {
                    // If the characters do not match, we only consider the result of excluding the current character of s
                    dp[i, j] = dp[i - 1, j];
                }
            }
        }
        
        // The result is the value in the bottom-right corner of the dp array
        return dp[m, n];
    }
}

Subscribe
Notify of

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments

Popular