Facebook Pixel

3628. Maximum Number of Subsequences After One Inserting

Problem Description

You are given a string s consisting of uppercase English letters.

The task is to find the maximum number of "LCT" subsequences that can be formed after inserting at most one uppercase English letter into the string.

A subsequence is a sequence that can be derived from the original string by deleting some or no elements without changing the order of the remaining elements. For example, "LCT" is a subsequence of "ALCTB" (formed by taking the 2nd, 3rd, and 5th characters).

You can:

  • Keep the string as is (insert nothing)
  • Insert exactly one uppercase English letter at any position in the string (including at the beginning or end)

The goal is to maximize the number of "LCT" subsequences in the resulting string.

For example, if the original string is "LLCTT", it contains 2 "LCT" subsequences (using the first L with C and first T, and first L with C and second T). If we insert another "C" at position 3 to get "LLCCTT", we would have 4 "LCT" subsequences total.

The solution works by:

  1. First counting the existing "LCT" subsequences in the original string by enumerating each "C" as the middle character and counting valid "L"s before it and "T"s after it
  2. Then considering what happens when we insert one additional letter:
    • Inserting "L": counts additional "CT" subsequences that would form with the new "L"
    • Inserting "T": counts additional "LC" subsequences that would form with the new "T"
    • Inserting "C": counts additional "LT" subsequences that would form with the new "C" in the middle

The final answer is the sum of the original count plus the maximum gain from inserting one letter.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that each "LCT" subsequence is formed by choosing one 'L', one 'C', and one 'T' in that order from the string. So we can think of counting these subsequences by fixing the middle character 'C' and counting valid combinations.

For any 'C' in the string, the number of "LCT" subsequences using that 'C' equals the number of 'L's before it multiplied by the number of 'T's after it. This is because we can pair any 'L' before with any 'T' after to form a valid subsequence.

When we consider inserting one additional character, we need to think about what new subsequences it creates:

  • If we insert an 'L', it can combine with any existing "CT" subsequence to form new "LCT" subsequences
  • If we insert a 'T', it can combine with any existing "LC" subsequence to form new "LCT" subsequences
  • If we insert a 'C', it acts as a new middle point and can combine with any 'L' before its position and any 'T' after its position

The clever part is realizing we can calculate all these possibilities efficiently in a single pass through the string. As we traverse, we maintain running counts of 'L's seen so far and 'T's remaining. This allows us to:

  1. Calculate existing "LCT" subsequences when we encounter a 'C'
  2. Track the maximum potential gain from inserting a 'C' at any position (which would be l * r at that position)
  3. Count "LC" and "CT" subsequences for potential 'T' and 'L' insertions

By considering all insertion possibilities and taking the maximum gain, we ensure we find the optimal solution.

Learn more about Greedy, Dynamic Programming and Prefix Sum patterns.

Solution Approach

The implementation consists of two main parts: counting existing "LCT" subsequences and calculating the maximum gain from inserting one character.

Part 1: Counting existing "LCT" subsequences

We traverse the string once while maintaining:

  • l: count of 'L's seen so far (to the left of current position)
  • r: count of 'T's remaining (to the right of current position, initialized to total 'T' count)
  • ans: total count of "LCT" subsequences

For each character:

  1. First decrement r if the current character is 'T' (removing it from the right count)
  2. If the current character is 'C', add l * r to ans (all possible "LCT" using this 'C')
  3. Increment l if the current character is 'L' (adding it to the left count)

Part 2: Calculating maximum gain from insertion

We track mx as the maximum additional subsequences we can get from inserting one character:

  1. Inserting 'C': During the main traversal, we track max(l * r) at each position. This represents the maximum "LT" subsequences we could create by inserting 'C' at the optimal position.

  2. Inserting 'L' or 'T': We use a helper function calc(t) to count two-character subsequences:

    • For inserting 'L': call calc("CT") to count existing "CT" subsequences
    • For inserting 'T': call calc("LC") to count existing "LC" subsequences

The calc function works by:

  • Maintaining a counter a for occurrences of the first character in pattern t
  • When we see the second character of pattern t, we add a to the count (each first character can pair with this second character)
  • This efficiently counts all subsequences of the two-character pattern

Final calculation

The maximum number of "LCT" subsequences is ans + mx, where:

  • ans is the count from the original string
  • mx is the maximum gain from inserting one character (the best among inserting 'L', 'C', or 'T')

The time complexity is O(n) where n is the length of the string, as we make at most three passes through the string. The space complexity is O(1) as we only use a constant amount of extra variables.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with the string s = "LLCTT".

Step 1: Count existing "LCT" subsequences

We traverse the string while tracking:

  • l = count of 'L's seen so far
  • r = count of 'T's remaining (initially 2)
  • ans = total "LCT" subsequences

Position by position:

  • Position 0 ('L'): l=0, r=2 → No 'C', so no subsequences. Update l=1
  • Position 1 ('L'): l=1, r=2 → No 'C', so no subsequences. Update l=2
  • Position 2 ('C'): l=2, r=2 → Found 'C'! Add 2*2=4 to ans. Now ans=4
  • Position 3 ('T'): First decrement r=1, then l=2, r=1 → No 'C', no new subsequences
  • Position 4 ('T'): First decrement r=0, then l=2, r=0 → No 'C', no new subsequences

Original string has 4 "LCT" subsequences: L₁CT₁, L₁CT₂, L₂CT₁, L₂CT₂

Step 2: Calculate maximum gain from insertion

During traversal, we also track the maximum gain from inserting each letter:

  1. Inserting 'C': Track max(l * r) at each position:

    • Position 0: l=0, r=20*2=0
    • Position 1: l=1, r=21*2=2
    • Position 2: l=2, r=22*2=4
    • Position 3: l=2, r=12*1=2
    • Position 4: l=2, r=02*0=0
    • Maximum gain from inserting 'C': 4
  2. Inserting 'L': Count "CT" subsequences using calc("CT"):

    • Track 'C' count, increment when we see 'T'
    • 'L': skip
    • 'L': skip
    • 'C': set counter a=1
    • 'T': found second char, add a=1 to count → count=1
    • 'T': found second char, add a=1 to count → count=2
    • Total "CT" subsequences: 2 (so inserting 'L' would add 2 more "LCT")
  3. Inserting 'T': Count "LC" subsequences using calc("LC"):

    • Track 'L' count, increment when we see 'C'
    • 'L': set counter a=1
    • 'L': increment counter a=2
    • 'C': found second char, add a=2 to count → count=2
    • 'T': skip
    • 'T': skip
    • Total "LC" subsequences: 2 (so inserting 'T' would add 2 more "LCT")

Step 3: Find the maximum

  • Original count: 4
  • Best insertion gain: max(4, 2, 2) = 4 (from inserting 'C')
  • Final answer: 4 + 4 = 8

Indeed, if we insert 'C' at position 2 to get "LLCCTT", we would have:

  • 2 L's × 2 C's × 2 T's = 8 total "LCT" subsequences

Solution Implementation

1class Solution:
2    def numOfSubsequences(self, s: str) -> int:
3        def count_two_char_subsequences(target_pair: str) -> int:
4            """
5            Count subsequences of two characters where target_pair[0] comes before target_pair[1]
6          
7            Args:
8                target_pair: A string of length 2 representing the subsequence pattern
9          
10            Returns:
11                Number of valid subsequences
12            """
13            subsequence_count = 0
14            first_char_count = 0
15          
16            # For each character, if it matches the second character of the pair,
17            # it can form subsequences with all previous occurrences of the first character
18            for char in s:
19                if char == target_pair[1]:
20                    subsequence_count += first_char_count
21                if char == target_pair[0]:
22                    first_char_count += 1
23          
24            return subsequence_count
25      
26        # Initialize counters for 'L' on the left and 'T' on the right
27        left_l_count = 0
28        right_t_count = s.count("T")
29      
30        # Track the answer and maximum possible additional subsequences
31        total_subsequences = 0
32        max_additional_subsequences = 0
33      
34        # Process each character in the string
35        for char in s:
36            # Update right 'T' count (we're moving left to right)
37            if char == "T":
38                right_t_count -= 1
39          
40            # If current character is 'C', it can form "LCT" subsequences
41            # with 'L's on its left and 'T's on its right
42            if char == "C":
43                total_subsequences += left_l_count * right_t_count
44          
45            # Update left 'L' count
46            if char == "L":
47                left_l_count += 1
48          
49            # Track the maximum potential for additional subsequences
50            max_additional_subsequences = max(max_additional_subsequences, 
51                                             left_l_count * right_t_count)
52      
53        # Also consider "LC" and "CT" two-character subsequences
54        max_additional_subsequences = max(max_additional_subsequences,
55                                         count_two_char_subsequences("LC"),
56                                         count_two_char_subsequences("CT"))
57      
58        # Add the maximum additional subsequences to the total
59        total_subsequences += max_additional_subsequences
60      
61        return total_subsequences
62
1class Solution {
2    private char[] charArray;
3
4    public long numOfSubsequences(String S) {
5        // Convert string to char array for efficient traversal
6        charArray = S.toCharArray();
7      
8        // Initialize counters for 'L' on the left and 'T' on the right
9        int leftLCount = 0;
10        int rightTCount = 0;
11      
12        // Count total number of 'T' characters (initially all are on the right)
13        for (char ch : charArray) {
14            if (ch == 'T') {
15                rightTCount++;
16            }
17        }
18      
19        // Count LCT subsequences and track maximum potential
20        long totalLCTCount = 0;
21        long maxPotential = 0;
22      
23        for (char ch : charArray) {
24            // Move 'T' from right side to processed side
25            if (ch == 'T') {
26                rightTCount--;
27            }
28          
29            // When we encounter 'C', count all possible LCT subsequences
30            // formed with 'L's on the left and 'T's on the right
31            if (ch == 'C') {
32                totalLCTCount += (long) leftLCount * rightTCount;
33            }
34          
35            // Add current character to left side count if it's 'L'
36            if (ch == 'L') {
37                leftLCount++;
38            }
39          
40            // Track maximum potential LCT count at each position
41            maxPotential = Math.max(maxPotential, (long) leftLCount * rightTCount);
42        }
43      
44        // Calculate maximum between current max and two-character subsequences
45        maxPotential = Math.max(maxPotential, Math.max(
46            calculateTwoCharSubsequences("LC"), 
47            calculateTwoCharSubsequences("CT")
48        ));
49      
50        // Add the maximum potential to get final answer
51        totalLCTCount += maxPotential;
52      
53        return totalLCTCount;
54    }
55
56    /**
57     * Calculates the number of two-character subsequences in the string
58     * @param pattern The two-character pattern to search for (e.g., "LC" or "CT")
59     * @return Number of subsequences matching the pattern
60     */
61    private long calculateTwoCharSubsequences(String pattern) {
62        long subsequenceCount = 0;
63        int firstCharCount = 0;
64      
65        // Count subsequences where first character appears before second
66        for (char ch : charArray) {
67            // If current character matches the second character of pattern,
68            // it can form subsequences with all previous first characters
69            if (ch == pattern.charAt(1)) {
70                subsequenceCount += firstCharCount;
71            }
72          
73            // Count occurrences of the first character
74            if (ch == pattern.charAt(0)) {
75                firstCharCount++;
76            }
77        }
78      
79        return subsequenceCount;
80    }
81}
82
1class Solution {
2public:
3    long long numOfSubsequences(string s) {
4        // Lambda function to count subsequences of a specific 2-character pattern
5        auto countTwoCharSubsequences = [&](string pattern) {
6            long long subsequenceCount = 0;  // Total count of valid subsequences
7            long long firstCharCount = 0;    // Count of first character seen so far
8          
9            for (char currentChar : s) {
10                // If we find the second character of the pattern,
11                // we can form subsequences with all previous first characters
12                if (currentChar == pattern[1]) {
13                    subsequenceCount += firstCharCount;
14                }
15                // Update count of first character
16                if (currentChar == pattern[0]) {
17                    firstCharCount++;
18                }
19            }
20            return subsequenceCount;
21        };
22
23        // Initialize counters for 'L' on left and 'T' on right
24        long long leftLCount = 0;
25        long long rightTCount = count(s.begin(), s.end(), 'T');
26      
27        // Variables to track the answer and maximum L*T product
28        long long totalSubsequences = 0;
29        long long maxLTProduct = 0;
30      
31        // Main loop: process each character to count "LCT" subsequences
32        for (char currentChar : s) {
33            // Update right T count (moving from right to left conceptually)
34            if (currentChar == 'T') {
35                rightTCount--;
36            }
37          
38            // If current character is 'C', it can form subsequences with
39            // all 'L's on its left and all 'T's on its right
40            if (currentChar == 'C') {
41                totalSubsequences += leftLCount * rightTCount;
42            }
43          
44            // Update left L count
45            if (currentChar == 'L') {
46                leftLCount++;
47            }
48          
49            // Track maximum product of L's on left and T's on right
50            maxLTProduct = max(maxLTProduct, leftLCount * rightTCount);
51        }
52      
53        // Consider other two-character subsequences and update maximum
54        maxLTProduct = max(maxLTProduct, countTwoCharSubsequences("LC"));
55        maxLTProduct = max(maxLTProduct, countTwoCharSubsequences("CT"));
56      
57        // Add the maximum value to get final answer
58        totalSubsequences += maxLTProduct;
59      
60        return totalSubsequences;
61    }
62};
63
1/**
2 * Counts the number of valid subsequences in a string containing 'L', 'C', and 'T' characters.
3 * The function calculates subsequences based on specific patterns and combinations.
4 * @param s - The input string containing characters 'L', 'C', and 'T'
5 * @returns The total number of valid subsequences
6 */
7function numOfSubsequences(s: string): number {
8    /**
9     * Helper function to calculate the number of subsequences for a given two-character pattern.
10     * Counts how many times the pattern appears as a subsequence in the original string.
11     * @param pattern - A two-character string representing the pattern to search for
12     * @returns The count of subsequences matching the pattern
13     */
14    const calculatePatternCount = (pattern: string): number => {
15        let subsequenceCount: number = 0;
16        let firstCharCount: number = 0;
17      
18        // Iterate through each character in the string
19        for (const char of s) {
20            // If we find the second character of the pattern, add all possible combinations
21            if (char === pattern[1]) {
22                subsequenceCount += firstCharCount;
23            }
24            // If we find the first character of the pattern, increment its counter
25            if (char === pattern[0]) {
26                firstCharCount++;
27            }
28        }
29      
30        return subsequenceCount;
31    };
32
33    // Initialize counters for 'L' characters on the left and 'T' characters on the right
34    let leftLCount: number = 0;
35    let rightTCount: number = 0;
36  
37    // Count all 'T' characters initially (they are all on the "right" at the start)
38    for (const char of s) {
39        if (char === 'T') {
40            rightTCount++;
41        }
42    }
43
44    // Initialize the answer and maximum value tracker
45    let totalSubsequences: number = 0;
46    let maxValue: number = 0;
47  
48    // Process each character in the string from left to right
49    for (const char of s) {
50        // Move 'T' from right side to processed side
51        if (char === 'T') {
52            rightTCount--;
53        }
54        // When we encounter 'C', calculate LCT subsequences
55        if (char === 'C') {
56            totalSubsequences += leftLCount * rightTCount;
57        }
58        // Count 'L' characters that have been processed
59        if (char === 'L') {
60            leftLCount++;
61        }
62        // Track the maximum product of L and T counts
63        maxValue = Math.max(maxValue, leftLCount * rightTCount);
64    }
65
66    // Check for additional patterns and update maximum value
67    maxValue = Math.max(maxValue, calculatePatternCount('LC'));
68    maxValue = Math.max(maxValue, calculatePatternCount('CT'));
69  
70    // Add the maximum value to the total subsequences
71    totalSubsequences += maxValue;
72  
73    return totalSubsequences;
74}
75

Time and Space Complexity

The time complexity is O(n), where n is the length of the string s. The algorithm makes a total of three passes through the string:

  • The first pass counts all occurrences of "T" using s.count("T"), which takes O(n) time
  • The second pass iterates through the string once to calculate ans and track the maximum value of l * r, which takes O(n) time
  • Two additional passes are made through the calc function (called twice with different parameters), each taking O(n) time

Since these operations are performed sequentially (not nested), the overall time complexity remains O(n).

The space complexity is O(1). The algorithm only uses a constant amount of extra space for variables (l, r, ans, mx, cnt, a, and c), regardless of the input size. No additional data structures that scale with the input are created.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrect Order of Counter Updates

One of the most common mistakes is updating the counters in the wrong order when traversing the string. The critical pitfall is updating left_l_count or right_t_count before using them to calculate subsequences for the current 'C'.

Incorrect Implementation:

for char in s:
    if char == "L":
        left_l_count += 1  # WRONG: Updating before using
    if char == "C":
        total_subsequences += left_l_count * right_t_count
    if char == "T":
        right_t_count -= 1  # This would also be wrong if done after using

Why it's wrong: If we increment left_l_count when we see an 'L' before processing a potential 'C' at the same position, we're incorrectly including the current 'L' in the count of 'L's that come before the current position.

Correct Order:

for char in s:
    # 1. First, update right count (remove current T from right side)
    if char == "T":
        right_t_count -= 1
  
    # 2. Then, use the counts if current is 'C'
    if char == "C":
        total_subsequences += left_l_count * right_t_count
  
    # 3. Finally, update left count (add current L to left side)
    if char == "L":
        left_l_count += 1

2. Forgetting to Track Maximum Insertion Position for 'C'

Another pitfall is only considering the maximum left_l_count * right_t_count at positions where 'C' already exists, rather than at all positions in the string.

Incorrect Implementation:

for char in s:
    if char == "T":
        right_t_count -= 1
    if char == "C":
        total_subsequences += left_l_count * right_t_count
        # WRONG: Only updating max when we see 'C'
        max_additional_subsequences = max(max_additional_subsequences, 
                                         left_l_count * right_t_count)
    if char == "L":
        left_l_count += 1

Correct Implementation:

for char in s:
    if char == "T":
        right_t_count -= 1
    if char == "C":
        total_subsequences += left_l_count * right_t_count
    if char == "L":
        left_l_count += 1
  
    # Update max at EVERY position, not just at 'C' positions
    max_additional_subsequences = max(max_additional_subsequences, 
                                     left_l_count * right_t_count)

3. Double-Counting When Inserting Characters

A subtle pitfall occurs when not understanding that inserting a character creates new subsequences but doesn't affect the existing count. The mistake is thinking that inserting 'C' would somehow change the existing "LCT" count beyond just adding new ones.

Key Understanding:

  • When we insert 'L': We only count additional "CT" subsequences (the new 'L' forms with existing 'C' and 'T')
  • When we insert 'C': We only count additional "LT" subsequences (existing 'L' and 'T' form with the new 'C')
  • When we insert 'T': We only count additional "LC" subsequences (existing 'L' and 'C' form with the new 'T')

The original subsequences remain unchanged; we're only adding to them.

4. Initialization Error for Right Count

Incorrect:

right_t_count = 0  # WRONG: Should start with total count of 'T'

Correct:

right_t_count = s.count("T")  # Start with all 'T's on the right

This ensures that at the beginning of traversal, all 'T's are considered to be "to the right" of our current position.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What's the relationship between a tree and a graph?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More