1 minute read

Problem Statement

problem

Brute Force [TLE]

class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        N = len(s)
        seen = set()

        def isPalindrome(curr):
            l, r = 0, len(curr) - 1
            while l < r:
                if curr[l] != curr[r]:
                    return False
                l += 1
                r -= 1
            return True

        def dfs(i, curr):
            if i == N:
                if len(curr) == 3 and isPalindrome(curr):
                    seen.add(''.join(curr))
                return
            if len(curr) == 3:
                if isPalindrome(curr):
                    seen.add(''.join(curr))
                return
            dfs(i + 1, curr + [s[i]])
            dfs(i + 1, curr)


        for i in range(N):
            dfs(i, [])

        return len(seen)
class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        N = len(s)
        pos = defaultdict(int)
        res = set()
        for i, c in enumerate(s):
            if i >= 2 and c in pos:
                for j in range(pos[c] + 1, i):
                    res.add(c + s[j] + c)
            if c not in pos:
                pos[c] = i
        return len(res)

Improve Algorithm using first and last

class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        # Track the first and last occurrence of each character
        first = {}
        last = {}

        for i, c in enumerate(s):
            if c not in first:
                first[c] = i
            last[c] = i

        res = set()

        # Iterate over all characters in the string
        for c in first:
            if last[c] - first[c] > 1:  # Check if there's space for a middle character
                # Add all unique middle characters
                res.update({c + s[mid] + c for mid in range(first[c] + 1, last[c])})

        return len(res)

Editorial

Approach 1: Count Letters In-Between

class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        letters = set(s)
        ans = 0

        for letter in letters:
            i, j = s.index(letter), s.rindex(letter)
            between = set()

            for k in range(i + 1, j):
                between.add(s[k])

            ans += len(between)

        return ans

Python 1-liner:

class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        return sum([len(set(s[s.index(letter)+1:s.rindex(letter)])) for letter in set(s)])

Approach 2: Pre-Compute First and Last Indices

class Solution:
    def countPalindromicSubsequence(self, s: str) -> int:
        first = [-1] * 26
        last = [-1] * 26

        for i in range(len(s)):
            curr = ord(s[i]) - ord("a")
            if first[curr] == -1:
                first[curr] = i

            last[curr] = i

        ans = 0
        for i in range(26):
            if first[i] == -1:
                continue

            between = set()
            for j in range(first[i] + 1, last[i]):
                between.add(s[j])

            ans += len(between)

        return ans
  • time: O(n)
  • space: O(1)