Leetcode 1542. Find Longest Awesome Substring

Problem Explanation:

The problem requirement is to find the longest "awesome" substring from a given string s. Here, the word "awesome" is used to classify a special type of substring. An "awesome" substring is one in which we can make any number of swaps to form a palindrome.

A palindrome is a string that remains the same when its characters are reversed. For example, "madam" is a palindrome.

Let's walk through an example:

Example:

s = "213123"

In this string, the whole string "213123" itself is an "awesome" substring since we can rearrange it to form a palindrome "231132". Therefore, the longest possible "awesome" substring from s is of length 6.

Approach Explanation:

The solution applies the idea of binary numbers and prefix sum.

  1. It initializes the length of the answer to zero and the binary prefix to zero.

  2. It creates a vector with the size 1024 (for storing all combinations of binary for 10 digits), initializing all elements to the length of string s and it sets the prefix at position 0 to -1.

  3. It then operates a loop over the string and for each character, it toggles the bit at that position in the binary prefix.

  4. With the updated prefix it then checks the maximum length of the awesome substring comparing with the current length of string to the index of the same prefix stored earlier.

  5. Further, it checks all possibilities for all 10 digits if a single digit is added or removed to the current prefix to again get the maximum possible length.

  6. It then updates the minimum index for the current prefix in the prefix to index vector.

  7. Finally, it returns the length of the maximum awesome substring.

This algorithm uses a vector as a data structure to store prefix to index mapping for all possible combinations of 10 digits (hence size 1024).

Python Solution:

1
2python
3class Solution:
4  def longestAwesome(self, s: str) -> int:
5    ans = 0
6    prefix = 0 
7    prefixToIndex = [len(s)] * 1024
8    prefixToIndex[0] = -1
9
10    for i in range(len(s)):
11      prefix ^= 1 << int(s[i])
12      ans = max(ans, i - prefixToIndex[prefix])
13      for j in range(10):
14        ans = max(ans, i - prefixToIndex[prefix ^ 1 << j])
15      prefixToIndex[prefix] = min(prefixToIndex[prefix], i)
16
17    return ans

Java Solution:

1
2java
3public class Solution {
4  public int longestAwesome(String s) {
5    int ans = 0;
6    int prefix = 0; 
7    int[] prefixToIndex = new int[1024];
8    
9    Arrays.fill(prefixToIndex, s.length());
10    prefixToIndex[0] = -1;
11
12    for (int i = 0; i < s.length(); ++i) {
13      prefix ^= 1 << s.charAt(i) - '0';
14      ans = Math.max(ans, i - prefixToIndex[prefix]);
15      for (int j = 0; j < 10; ++j)
16        ans = Math.max(ans, i - prefixToIndex[prefix ^ 1 << j]);
17      prefixToIndex[prefix] = Math.min(prefixToIndex[prefix], i);
18    }
19
20    return ans;
21  }
22}

Javascript Solution:

1
2javascript
3class Solution {
4  longestAwesome(s) {
5    let ans = 0;
6    let prefix = 0; 
7    let prefixToIndex = new Array(1024).fill(s.length);
8    prefixToIndex[0] = -1;
9
10    for (let i = 0; i < s.length; ++i) {
11      prefix ^= 1 << parseInt(s[i]);
12      ans = Math.max(ans, i - prefixToIndex[prefix]);
13      for (let j = 0; j < 10; ++j)
14        ans = Math.max(ans, i - prefixToIndex[prefix ^ 1 << j]);
15      prefixToIndex[prefix] = Math.min(prefixToIndex[prefix], i);
16    }
17
18    return ans;
19  }
20}

C++ Solution:

1
2cpp
3class Solution {
4 public:
5  int longestAwesome(string s) {
6    int ans = 0;
7    int prefix = 0;  
8    vector<int> prefixToIndex(1024, s.length());
9    prefixToIndex[0] = -1;
10
11    for (int i = 0; i < s.length(); ++i) {
12      prefix ^= 1 << s[i] - '0';
13      ans = max(ans, i - prefixToIndex[prefix]);
14      for (int j = 0; j < 10; ++j)
15        ans = max(ans, i - prefixToIndex[prefix ^ 1 << j]);
16      prefixToIndex[prefix] = min(prefixToIndex[prefix], i);
17    }
18
19    return ans;
20  }
21};

C# Solution:

1
2csharp
3public class Solution {
4  public int LongestAwesome(string s) {
5    int ans = 0;
6    int prefix = 0; 
7    int[] prefixToIndex = Enumerable.Repeat(s.Length, 1024).ToArray();
8    prefixToIndex[0] = -1;
9
10    for (int i = 0; i < s.Length; ++i) {
11      prefix ^= 1 << s[i] - '0';
12      ans = Math.Max(ans, i - prefixToIndex[prefix]);
13      for (int j = 0; j < 10; ++j)
14        ans = Math.Max(ans, i - prefixToIndex[prefix ^ 1 << j]);
15      prefixToIndex[prefix] = Math.Min(prefixToIndex[prefix], i);
16    }
17
18    return ans;
19  }
20}

This solution approaches the problem by using a combination of bit manipulation (to keep track of the parity of each character) and a prefix sum array (to get the longest substring that satisfies the required conditions). The solution iterates through the given string and checks if the current prefix has been seen before (to get the longest substring), and also checks if adding or removing one digit from the current prefix results in a previously seen prefix (which would mean there is a longer “awesome” substring).# Analysis of the Solution

Given a string s, the algorithm iterates over the string in the first loop using O(n) time complexity where n is the length of the string. It also checks all possibilities of 10 digits in each iteration inside an inner loop. Therefore, the overall time complexity is O(n) * O(10) i.e., O(10n) which is linear time.

The space complexity of the algorithm depends on the size of the prefixToIndex vector. Here, the prefixToIndex size is 1024 which is constant. Thus, the space complexity is O(1).

Conclusion

This comparative analysis of different language solutions for finding the longest "awesome" substring in a given string provides significant insights. Each language solution utilizes the same core logic to solve the problem. However, the differences can be seen in the syntax and usage of language-specific features.

Your choice of the programming language ultimately depends on your project's specific needs and your personal preference. By understanding how the problem is solved in multiple languages, you can easily port the solution to another language if the need arises in the future. The fundamental understanding of the underlying algorithm is important, as it remains the same regardless of the programming language used.


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.


TA 👨‍🏫