Given a stringĀ sĀ consisting only of digits, find the length of theĀ longest substringĀ ofĀ lengthĀ 2kĀ (where k ā„ 1) such that the sum of left k digits is equal to the sum of right k digits. If no such valid substring exists, returnĀ 0.
Examples :Ā
Input: s = "1234123"
Output: 4
Explanation: The valid substring is s[1..4] = "2341", where the first half "23" has sum 5 and the second half "41" also has sum 5. Therefore, the length of the longest valid substring is 4.Input: s = "0000000"
Output: 6
Explanation: The valid substring is s[0..5] = "000000", where both halves "000" have a sum of 0. Therefore, the length of the longest valid substring is 6.
Table of Content
[Naive Approach] Using Brute Force - O(n * n * n) Time and O(1) Space
Use two nested loops to generate all even-length substrings and a third loop to calculate their left and right half sums, updating the maximum length whenever the two halves match.
#include <iostream>
#include <string>
using namespace std;
int findLength(string &s) {
int n = s.length();
int maxlen = 0;
// Choose starting point of every substring
for (int i = 0; i < n; i++) {
// Choose ending point of even length substring
for (int j = i + 1; j < n; j += 2) {
// Find length of current substring
int length = j - i + 1;
// Calculate left and right sums for current substring
int leftsum = 0;
int rightsum = 0;
for (int k = 0; k < length / 2; k++) {
leftsum += (s[i + k] - '0');
rightsum += (s[i + k + length / 2] - '0');
}
// Update result if needed
if (leftsum == rightsum && maxlen < length) {
maxlen = length;
}
}
}
return maxlen;
}
int main() {
string s = "1234123";
cout << findLength(s) << endl;
return 0;
}
class GFG {
static int findLength(String s) {
int n = s.length();
int maxlen = 0;
// Choose starting point of every substring
for (int i = 0; i < n; i++) {
// Choose ending point of even length substring
for (int j = i + 1; j < n; j += 2) {
// Find length of current substring
int length = j - i + 1;
// Calculate left and right sums for current substring
int leftsum = 0;
int rightsum = 0;
for (int k = 0; k < length / 2; k++) {
leftsum += (s.charAt(i + k) - '0');
rightsum += (s.charAt(i + k + length / 2) - '0');
}
// Update result if needed
if (leftsum == rightsum && maxlen < length) {
maxlen = length;
}
}
}
return maxlen;
}
public static void main(String[] args) {
String s = "1234123";
System.out.println(findLength(s));
}
}
def findLength(s):
n = len(s)
maxlen = 0
# Choose starting point of every substring
for i in range(n):
# Choose ending point of even length substring
for j in range(i + 1, n, 2):
# Find length of current substring
length = j - i + 1
half_len = length // 2
# Calculate left and right sums for current substring
leftsum = 0
rightsum = 0
for k in range(half_len):
# In Python, int(char) directly gives the integer value
leftsum += int(s[i + k])
rightsum += int(s[i + k + half_len])
# Update result if needed
if leftsum == rightsum and maxlen < length:
maxlen = length
return maxlen
if __name__ == "__main__":
s = "1234123"
print(findLength(s))
using System;
class GFG {
static int findLength(string s) {
int n = s.Length;
int maxlen = 0;
// Choose starting point of every substring
for (int i = 0; i < n; i++) {
// Choose ending point of even length substring
for (int j = i + 1; j < n; j += 2) {
// Find length of current substring
int length = j - i + 1;
// Calculate left and right sums for current substring
int leftsum = 0;
int rightsum = 0;
for (int k = 0; k < length / 2; k++) {
leftsum += (s[i + k] - '0');
rightsum += (s[i + k + length / 2] - '0');
}
// Update result if needed
if (leftsum == rightsum && maxlen < length) {
maxlen = length;
}
}
}
return maxlen;
}
public static void Main() {
string s = "1234123";
Console.Write(findLength(s));
}
}
function findLength(s) {
let n = s.length;
let maxlen = 0;
// Choose starting point of every substring
for (let i = 0; i < n; i++) {
// Choose ending point of even length substring
for (let j = i + 1; j < n; j += 2) {
// Find length of current substring
let length = j - i + 1;
// Calculate left and right sums for current substring
let leftsum = 0;
let rightsum = 0;
for (let k = 0; k < length / 2; k++) {
leftsum += parseInt(s[i + k], 10);
rightsum += parseInt(s[i + k + length / 2], 10);
}
// Update result if needed
if (leftsum === rightsum && maxlen < length) {
maxlen = length;
}
}
}
return maxlen;
}
// Driver code
let s = "1234123";
console.log( findLength(s));
Output
4
[Better Approach] Using Prefix Sums - O(n * n) Time and O(n) Space
Use a 1D array to store the cumulative sum of digits up to any index. This allows to find the sum of any substring in O(1) time. By checking all possible even-length substrings and comparing the sum of their left and right halves using this array, we drop the time complexity to O( n * n ) while using only O(n) extra space.
For example, s = "1234123"
- Step 1 (Prefix Sum Array): Create an array sum that stores the cumulative sum. For this string, the array becomes [0, 1, 3, 6, 10, 11, 14, 21].
- Step 2 (Length 2): Check substrings of length 2. For "23" (indices 1 to 2), the left sum is sum[2] - sum[1] = 3 - 1 = 2, and the right sum is sum[3] - sum[2] = 6 - 3 = 3. No match.
- Step 3 (Length 4 - Match): Check substrings of length 4. Consider the chunk "2341" (indices 1 to 4): Left Half Sum: sum[3] - sum[1] = 6 - 1 = 5. Right Half Sum: sum[5] - sum[3] = 11 - 6 = 5. Since the sums match (5 == 5), we update maxlen = 4.
(The algorithm continues to check length 6 strings, but they fail. The final answer returned is 4).
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
int findLength(string &s) {
int n = s.length();
// Array to store cumulative sum from the first digit to the nth digit
vector<int> sum(n + 1, 0);
// Store cumulative sum of digits from first to last digit
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + (s[i - 1] - '0');
}
int maxlen = 0;
// Consider all even length substrings one by one
for (int len = 2; len <= n; len += 2) {
// Iterate through all possible starting indices for the current length
for (int i = 0; i <= n - len; i++) {
// If the sum of the first half equals the sum of the second half, update maxlen
if (sum[i + len / 2] - sum[i] == sum[i + len] - sum[i + len / 2]) {
maxlen = max(maxlen, len);
}
}
}
return maxlen;
}
int main() {
string s = "1234123";
cout << findLength(s) << endl;
return 0;
}
class GFG {
static int findLength(String s) {
int n = s.length();
// Array to store cumulative sum from the first digit to the nth digit
int[] sum = new int[n + 1];
sum[0] = 0;
// Store cumulative sum of digits from first to last digit
for (int i = 1; i <= n; i++) {
sum[i] = sum[i - 1] + (s.charAt(i - 1) - '0');
}
int maxlen = 0;
// Consider all even length substrings one by one
for (int len = 2; len <= n; len += 2) {
// Iterate through all possible starting indices for the current length
for (int i = 0; i <= n - len; i++) {
// If the sum of the first half equals the sum of the second half, update maxlen
if (sum[i + len / 2] - sum[i] == sum[i + len] - sum[i + len / 2]) {
maxlen = Math.max(maxlen, len);
}
}
}
return maxlen;
}
public static void main(String[] args) {
String s = "1234123";
System.out.println(findLength(s));
}
}
def findLength(s):
n = len(s)
# Array to store cumulative sum from the first digit to the nth digit
sum_arr = [0] * (n + 1)
# Store cumulative sum of digits from first to last digit
for i in range(1, n + 1):
# Convert chars to int
sum_arr[i] = sum_arr[i - 1] + int(s[i - 1])
maxlen = 0
# Consider all even length substrings one by one
for length in range(2, n + 1, 2):
for i in range(0, n - length + 1):
# If the sum of the first half equals
# the sum of the second half, update maxlen
if (sum_arr[i + length // 2] - sum_arr[i] ==
sum_arr[i + length] - sum_arr[i + length // 2]):
maxlen = max(maxlen, length)
return maxlen
if __name__ == "__main__":
s = "1234123"
print(findLength(s))
using System;
class GFG {
static int findLength(string s) {
int n = s.Length;
// To store cumulative sum from the first digit to the nth digit
int[] sum = new int[n + 1];
sum[0] = 0;
// Store cumulative sum of digits from first to last digit
for (int i = 1; i <= n; i++) {
// Convert chars to int
sum[i] = sum[i - 1] + (s[i - 1] - '0');
}
int maxlen = 0;
// Consider all even length substrings one by one
for (int len = 2; len <= n; len += 2) {
// Iterate through all possible starting indices for the current length
for (int i = 0; i <= n - len; i++) {
int leftSum = sum[i + len / 2] - sum[i];
int rightSum = sum[i + len] - sum[i + len / 2];
// If the sum of the first half equals the sum of the second half, update maxlen
if (leftSum == rightSum) {
maxlen = Math.Max(maxlen, len);
}
}
}
return maxlen;
}
public static void Main() {
string s = "1234123";
Console.WriteLine(findLength(s));
}
}
function findLength(s) {
let n = s.length;
// To store cumulative sum from the first digit to the nth digit
let sum = new Array(n + 1).fill(0);
// Store cumulative sum of digits from first to last digit
for (let i = 1; i <= n; i++) {
// Convert chars to int
sum[i] = sum[i - 1] + parseInt(s[i - 1], 10);
}
let maxlen = 0;
// Consider all even length substrings one by one
for (let len = 2; len <= n; len += 2) {
// Iterate through all possible starting indices for the current length
for (let i = 0; i <= n - len; i++) {
let leftSum = sum[i + Math.floor(len / 2)] - sum[i];
let rightSum = sum[i + len] - sum[i + Math.floor(len / 2)];
// If the sum of the first half equals the sum of the second half, update maxlen
if (leftSum === rightSum) {
maxlen = Math.max(maxlen, len);
}
}
}
return maxlen;
}
// Driver code
let s = "1234123";
console.log(findLength(s));
Output
4
[Expected Approach] Using Midpoint Expansion - O(n * n) Time and O(1) Space
Instead of using extra space for prefix sums, this approach considers every possible split point in the string. For each potential midpoint, it uses two pointers to expand outwards to the left and right. By maintaining the running sum on both sides during the expansion, it checks for equal sums in O(n * n) time while using only O(1) extra space.
For example:s= "1234123"
- Step 1 (Initialize): Iterate through all possible midpoints i of the string.
- Step 2 (Midpoint i = 2 - Expand 1): Set l = 2 (character '3') and r = 3 (character '4'). Here, lsum is 3 and rsum is 4. They do not match.
- Step 3 (Midpoint i = 2 - Expand 2): Move pointers outward to l = 1 (character '2') and r = 4 (character '1'). The left sum becomes 3 + 2 = 5 and the right sum becomes 4 + 1 = 5.
- Step 4 (Match): The sums are equal (5 == 5), so we update the maximum length: maxlen = r - l + 1 = 4.
(The algorithm continues to check other midpoints, but no larger substring matches. The final answer returned is 4).
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
int findLength(string &s) {
int n = s.length();
int maxlen = 0;
// Consider all possible midpoints one by one
for (int i = 0; i <= n - 2; i++) {
/* For current midpoint 'i', keep expanding substring on
both sides, if sum of both sides becomes equal update
maxlen */
int l = i, r = i + 1;
/* Initialize left and right sum */
int lsum = 0, rsum = 0;
/* Move on both sides till indexes go out of bounds */
while (r < n && l >= 0) {
lsum += s[l] - '0';
rsum += s[r] - '0';
if (lsum == rsum) {
maxlen = max(maxlen, r - l + 1);
}
l--;
r++;
}
}
return maxlen;
}
int main() {
string s = "1234123";
cout << findLength(s) << endl;
return 0;
}
class GFG {
static int findLength(String s) {
int n = s.length();
int maxlen = 0;
// Consider all possible midpoints one by one
for (int i = 0; i <= n - 2; i++) {
/* For current midpoint 'i', keep expanding substring on
both sides; if the sum of both sides becomes equal,
update maxlen */
int l = i, r = i + 1;
/* Initialize left and right sum */
int lsum = 0, rsum = 0;
/* Move on both sides till indexes go out of bounds */
while (r < n && l >= 0) {
lsum += s.charAt(l) - '0';
rsum += s.charAt(r) - '0';
if (lsum == rsum) {
maxlen = Math.max(maxlen, r - l + 1);
}
l--;
r++;
}
}
return maxlen;
}
public static void main(String[] args) {
String s = "1234123";
System.out.println(findLength(s));
}
}
def findLength(s):
n = len(s)
# To store cumulative total from first digit to nth digit
total = [0] * (n + 1)
# Store cumulative total of digits from first to last digit
for i in range(1, n + 1):
# Convert chars to int
total[i] = total[i - 1] + int(s[i - 1])
ans = 0
# Consider all even length substrings one by one
l = 2
while l <= n:
for i in range(n - l + 1):
# If the sum of the first half equals the sum of the second half, update ans
if total[i + l // 2] - total[i] == total[i + l] - total[i + l // 2]:
ans = max(ans, l)
l += 2
return ans
if __name__ == "__main__":
s = "1234123"
print(findLength(s))
using System;
public class GFG {
static int findLength(string s) {
int n = s.Length;
int maxlen = 0;
// Consider all possible midpoints one by one
for (int i = 0; i <= n - 2; i++) {
/* For current midpoint 'i', keep expanding substring on
both sides; if the sum of both sides becomes equal,
update maxlen */
int l = i, r = i + 1;
/* Initialize left and right sum */
int lsum = 0, rsum = 0;
/* Move on both sides till indexes go out of bounds */
while (r < n && l >= 0) {
lsum += s[l] - '0';
rsum += s[r] - '0';
if (lsum == rsum) {
maxlen = Math.Max(maxlen, r - l + 1);
}
l--;
r++;
}
}
return maxlen;
}
public static void Main() {
string s = "1234123";
Console.WriteLine(findLength(s));
}
}
function findLength(s) {
let n = s.length;
let maxlen = 0;
// Consider all possible midpoints one by one
for (let i = 0; i <= n - 2; i++) {
/* For current midpoint 'i', keep expanding substring on
both sides; if the sum of both sides becomes equal,
update maxlen */
let l = i;
let r = i + 1;
/* Initialize left and right sum */
let lsum = 0;
let rsum = 0;
/* Move on both sides till indexes go out of bounds */
while (r < n && l >= 0) {
// equivalent to - '0'
lsum += s.charCodeAt(l) - 48;
rsum += s.charCodeAt(r) - 48;
if (lsum === rsum) {
maxlen = Math.max(maxlen, r - l + 1);
}
l--;
r++;
}
}
return maxlen;
}
// Driver code
let s = "1234123";
console.log(findLength(s));
Output
4