2 minute read

Problem Statement

1653

Memoization Approach - TLE

class Solution:

    def dfs(self, i, s, count, memo):
        if i == len(s):
            return count if count > 0 else float('inf')
        if (i, s, count) in memo:
            return memo[(i, s, count)]
        remove_a = remove_b = skip = float('inf')
        if i - 1 >= 0 and s[i - 1] == 'b' and s[i] == 'a':
            remove_b = self.dfs(i - 1, s[:i - 1] + s[i:], count + 1, memo)
            remove_a = self.dfs(i - 1, s[:i] + s[i + 1:], count + 1, memo)
        else:
            skip = self.dfs(i + 1, s, count, memo)

        memo[(i, s, count)] = min(remove_a, remove_b, skip)
        return memo[(i, s, count)]

    def minimumDeletions(self, s: str) -> int:
        if len(s) == 1:
            return 0
        if len(set(s)) == 1:
            return 0
        memo = defaultdict()
        return self.dfs(1, s, 0, memo)

Editorial

Approach 1: Three-Pass Count Method

class Solution:
    def minimumDeletions(self, s: str) -> int:
        n = len(s)
        count_a = [0] * n
        count_b = [0] * n
        b_count = 0

        # First pass: compute count_b which stores the number of
        # 'b' characters to the left of the current position.
        for i in range(n):
            count_b[i] = b_count
            if s[i] == "b":
                b_count += 1

        a_count = 0
        # Second pass: compute count_a which stores the number of
        # 'a' characters to the right of the current position
        for i in range(n - 1, -1, -1):
            count_a[i] = a_count
            if s[i] == "a":
                a_count += 1

        min_deletions = n
        # Third pass: iterate through the string to find the minimum deletions
        for i in range(n):
            min_deletions = min(min_deletions, count_a[i] + count_b[i])
        return min_deletions

Approach 2: Combined Pass Method

class Solution:
    def minimumDeletions(self, s: str) -> int:
        n = len(s)
        count_a = [0] * n
        a_count = 0

        # First pass: compute count_a which stores the number of
        # 'a' characters to the right of the current position
        for i in range(n - 1, -1, -1):
            count_a[i] = a_count
            if s[i] == "a":
                a_count += 1

        min_deletions = n
        b_count = 0
        # Second pass: compute minimum deletions on the fly
        for i in range(n):
            min_deletions = min(count_a[i] + b_count, min_deletions)
            if s[i] == "b":
                b_count += 1

        return min_deletions

Approach 3: Two-Variable Method

class Solution:
    def minimumDeletions(self, s: str) -> int:
        n = len(s)
        a_count = sum(1 for ch in s if ch == "a")

        b_count = 0
        min_deletions = n

        # Second pass: iterate through the string to compute minimum deletions
        for ch in s:
            if ch == "a":
                a_count -= 1
            min_deletions = min(min_deletions, a_count + b_count)
            if ch == "b":
                b_count += 1

        return min_deletions

Approach 4: Using stack (one pass)

class Solution:
    def minimumDeletions(self, s: str) -> int:
        char_stack = []
        delete_count = 0

        # Iterate through each character in the string
        for char in s:
            # If stack is not empty, top of stack is 'b',
            # and current char is 'a'
            if char_stack and char_stack[-1] == "b" and char == "a":
                char_stack.pop()  # Remove 'b' from stack
                delete_count += 1  # Increment deletion count
            else:
                char_stack.append(char)  # Append current character to stack

        return delete_count

Approach 5: Using DP (One Pass)

class Solution:
    def minimumDeletions(self, s: str) -> int:
        n = len(s)
        dp = [0] * (n + 1)
        b_count = 0

        # dp[i]: The number of deletions required to
        # balance the substring s[0, i)
        for i in range(n):
            if s[i] == "b":
                dp[i + 1] = dp[i]
                b_count += 1
            else:
                # Two cases: remove 'a' or keep 'a'
                dp[i + 1] = min(dp[i] + 1, b_count)

        return dp[n]