Leetcode 1525. Number of Good Ways to Split a String
Problem Explanation:
The problem is about splitting a given string into two non-empty strings in such a way that the number of distinct letters in both strings are the same. One must find the total number of such "good" splits in the string.
Let's walk through an example: Suppose you have a string "aacaba", you can split it in five ways as:
1 2 3("a", "acaba") 4("aa", "caba") 5("aac", "aba") 6("aaca", "ba") 7("aacab", "a")
Among these, two splits ("aac", "aba") and ("aaca", "ba") are good splits because the number of distinct letters in both strings is the same (2 in both cases). Hence, the output should be 2 for "aacaba".
Approach of the Solution:
The solution can be achieved through two-pointer technique and dynamic programming. To check the number of distinct characters in left and right part at each position, we use prefix and suffix arrays. The prefix array keeps a count of unique letters in the string from the start to the current position, while the suffix array does the same from the end to the current position. Then for each position, we compare the count stored in prefix and suffix arrays. If the count is the same, we increment the count of good splits.
Python Solution:
python
1 2python 3class Solution: 4 def numSplits(self, s: str) -> int: 5 n = len(s) 6 prefix = [0]*n 7 suffix = [0]*n 8 seen = set() 9 10 for i in range(n): 11 seen.add(s[i]) 12 prefix[i] = len(seen) 13 14 seen.clear() 15 16 for i in range(n-1, -1, -1): 17 seen.add(s[i]) 18 suffix[i] = len(seen) 19 20 return sum(prefix[i] == suffix[i+1] for i in range(n-1))
This Python code has a time complexity of O(n) where n is the the length of string s, and a space complexity of O(n).
Java Solution:
java
1 2java 3import java.util.*; 4 5class Solution { 6 public int numSplits(String s) { 7 int n = s.length(); 8 int[] prefix = new int[n]; 9 int[] suffix = new int[n]; 10 Set<Character> seen = new HashSet<>(); 11 12 for (int i = 0; i < n; i++) { 13 seen.add(s.charAt(i)); 14 prefix[i] = seen.size(); 15 } 16 17 seen.clear(); 18 19 for (int i = n - 1; i >= 0; --i) { 20 seen.add(s.charAt(i)); 21 suffix[i] = seen.size(); 22 } 23 24 int ans = 0; 25 26 for (int i = 0; i + 1 < n; ++i) 27 if (prefix[i] == suffix[i + 1]) 28 ++ans; 29 30 return ans; 31 } 32}
This Java code has the same time complexity of O(n).
JavaScript Solution:
javascript
1 2javascript 3function numSplits(s) { 4 let n = s.length; 5 let prefix = new Array(n).fill(0); 6 let suffix = new Array(n).fill(0); 7 let seen = new Set(); 8 9 for (let i = 0; i < n; i++) { 10 seen.add(s.charAt(i)); 11 prefix[i] = seen.size; 12 } 13 14 seen = new Set(); 15 16 for (let i = n-1; i >= 0; i--) { 17 seen.add(s.charAt(i)); 18 suffix[i] = seen.size; 19 } 20 21 let count = 0; 22 for (let i = 0; i < n-1; i++) { 23 if (prefix[i] == suffix[i+1]) 24 ++count; 25 } 26 27 return count; 28}
The post-increment is a standard operation in JavaScript, which is why it's used in the code.The JavaScript solution has a time complexity of O(n) and space complexity of O(n), which makes it the most efficient solution. It utilizes two arrays, prefix and suffix, to store the count of distinct characters as we traverse the string from both ends. The Set data structure ensures that each character is counted once.
In conclusion, the problem of counting "good" splits of a string into two parts with equal number of distinct characters can be solved efficiently using a combination of dynamic programming, prefix and suffix arrays, two-pointer technique, and Set data structure in Python, Java, and JavaScript. All the solutions have time complexity of O(n) and space complexity of O(n), providing an efficient way to solve the problem. With understanding of these concepts, one can approach such problems with confidence.
Got a question?ย Ask the Teaching Assistantย anything you don't understand.
Still not clear? Ask in the Forum, ย Discordย orย Submitย the part you don't understand to our editors.