LeetCode 2262: Total Appeal of A String

link

Try all substrings

For a substring with end-points: (begin, end), length of the set() of characters is the appeal.

Time: \mathcal{O}(n^2), space: \mathcal{O}(\texttt{unique-char-count}).

class Solution:
    def appealSum(self, s: str) -> int:
        n = len(s)
        appeal = 0
        for begin in range(n):
            chars = set()
            for end in range(begin, n):
                chars.add(s[end])
                appeal += len(chars)

        return appeal

Prefix appeals

Above, we are already quite efficient, taking only \mathcal{O}(1) time per substring. So, if we want to be more efficient, say take total \mathcal{O}(n) time, we cannot iterate over all substrings. For each index we must find total appeal up to that index in \mathcal{O}(1) time.

Observations:

  1. There are (i+1) substrings that end at s[i].
  2. Appeal of a substring is at least 1 and at most len(substring).
  3. For a substring, it does not matter if we compute appeal left-to-right or right-to-left.

Say A(i) is the total appeal of the prefix s[0 : i+1], then it is related to A(i-1) in the below way:

Above, since "d" does not appear in the prefix "abc", it adds 1 to all previous substring-appeals. So, Appeal("abcd") = Appeal("abc") + len("abc") + 1, where the 1 comes from the one-length substring "d".

On the other hand, if "d" appears in the earlier prefix, it increases substring-appeals by 1 up to (but excluding) the index where we last saw "d":

So, if we keep track of two pieces of information: (1) which index we last saw a character (2) appeal of previous prefix, we can compute the total appeal of all substrings that end at an index in \mathcal{O}(1) time.

Time: \mathcal{O}(n), space: \mathcal{O}(\texttt{unique-char-count}).

class Solution:
    def appealSum(self, s: str) -> int:
        prev_appeal = 0
        total_appeal = 0
        last_seen_at = {}
        for i, c in enumerate(s):
            pos = last_seen_at.get(c, -1)
            curr_appeal = prev_appeal + (i-pos)
            total_appeal += curr_appeal
            
            last_seen_at[c] = i
            prev_appeal = curr_appeal

        return total_appeal

Leave a comment