Search code examples
pythondictionarycounting

Why is this too slow?


On LeetCode, this is accepted but fails the submission because it's too slow for a very long string. What am I doing that is too slow that I should speed up?

The goal is to count the unique number of characters in a string when splitting it up as many ways as possible.

def numSplits(s):
    good_splits = 0
    string1 = ""
    string2 = ""
    repeated_chars_st1 = dict()
    repeated_chars_st2 = dict()
    for i in range(len(s)):
        string1 += s[i]
        string2 = s[i+1:]
        for char in string1:
            if char in repeated_chars_st1:
                repeated_chars_st1[char] += 1
            else:
                repeated_chars_st1[char] = 1
        for char2 in string2:
            if char2 in repeated_chars_st2:
                repeated_chars_st2[char2] += 1
            else:
                repeated_chars_st2[char2] = 1
        left_counter = len(repeated_chars_st1.keys())
        right_counter = len(repeated_chars_st2.keys())
        if left_counter == right_counter:
            good_splits += 1
        
        repeated_chars_st1.clear()
        repeated_chars_st2.clear()
        
    return good_splits

print(numSplits('aacaba'))

Here is the LeetCode question:

You are given a string s.

A split is called good if you can split s into two non-empty strings sleft and sright where their concatenation is equal to s (i.e., sleft + sright = s) and the number of distinct letters in sleft and sright is the same.

Return the number of good splits you can make in s.

Example 1:

Input: s = "aacaba"

Output: 2

Explanation: There are 5 ways to split aacaba and 2 of them are good.

  • ("a", "acaba") Left string and right string contains 1 and 3 different letters respectively.

  • ("aa", "caba") Left string and right string contains 1 and 3 different letters respectively.

  • ("aac", "aba") Left string and right string contains 2 and 2 different letters respectively (good split).

  • ("aaca", "ba") Left string and right string contains 2 and 2 different letters respectively (good split).

  • ("aacab", "a") Left string and right string contains 3 and 1 different letters respectively.

Example 2:

Input: s = "abcd"

Output: 1

Explanation: Split the string as follows ("ab", "cd").

Constraints:

  • 1 <= s.length <= 10^5
  • s consists of only lowercase English letters.

Solution

  • Here's a fairly quick solution. Store unique chars seen for both left and right sides of the split in a set and collections.Counter, keep track of the current counts so that we don't have to make unnecessary calls to len, then iterate over the string updating the data-structures and counts when needed and break when the left is bigger than the right

    def numSplits(self, s: str) -> int:
        count = 0
        left = set()
        left_count = 0
        right = Counter(s)
        right_count = len(right)
        for c in s:
            if c not in left:
                left.add(c)
                left_count += 1
            right[c] -= 1
            if right[c] == 0:
                right_count -= 1
            if left_count == right_count:
                count += 1
            elif left_count > right_count:
                break
        return count