Given an array of binary strings arr[] of size N (1 <= N <= 103). The task is to find the maximum distance between any pair of these binary strings. The distance between two binary strings is calculated as the sum of their lengths after excluding the common prefix.
Examples:
Input: arr[] = { “01011”, “010110”, “0111”} Output: 6 Explanation: The strings with the maximum distance between them are “010110” and “0111”, where the common prefix is “01”, Hence, the sum of their lengths after excluding the common prefix: 4 + 2 = 6.
Input: arr[] = {“001”, “1”, “111111”} Output: 9 Explanation: The string “001” and “111111” have no common prefix, hence, the sum of their lengths after excluding the common prefix: 3 + 6 = 9.
Maximizing Distance in Binary Strings using Trie:
We need to use of a Trie data structure to efficiently find the maximum distance between binary strings in the given array. We’ll store the length of longest suffix from current node till its bottom leaf node. By traversing the Trie, we can find the maximum distance by considering the sum of lengths of non-overlapping substrings of binary strings, resulting in the desired maximum distance calculation. This approach is extremely more efficient than comparing every pair of binary strings directly.
Step-by-step approach:
TrieNode Class:
- Create a TrieNode class with attributes val for storing the length of string after excluding the common prefix, an ending flag, and left and right child pointers.
Build Trie:
- Create a buildTree() function to build a Trie from an array of binary strings (nums).
- Initialize a pointer cur to the root node and iterate through each binary string in given array arr[].
- For each character in the binary string:
- If it’s ‘0’, traverse to the left child (0) in the Trie. If the left child doesn’t exist, create it and update its val.
- If it’s ‘1’, traverse to the right child (1) in the Trie. If the right child doesn’t exist, create it and update its val.
- Mark the current node as an ending node (isEnding = true)
Calculate Maximum Distance:
- Create a maxDistance() function to calculate the maximum distance between binary strings using the constructed Trie.
- Create the Trie root node and build the Trie structure using buildTree() by above mentioned steps.
- Initialize max_distance = 0 and a queue (q) for breadth-first traversal.
- Start with the root node and push it into the queue.
- While the queue is not empty:
- Dequeue the front node cur.
- If cur has left or right children:
- If it has both left and right children, calculate the maximum distance as the sum of their val and update max_distance.
- If cur is an ending node, calculate the maximum distance considering either the left or right child with val and update max_distance.
- Enqueue the left and right children of cur, if they exist.
- Return the max_distance.
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
class TrieNode {
public :
int val;
bool isEnding;
TrieNode* left;
TrieNode* right;
TrieNode( int val)
: val(val)
, isEnding( false )
, left(nullptr)
, right(nullptr)
{
}
};
void buildTree(TrieNode* root, vector<string>& nums)
{
for ( int i = 0; i < nums.size(); i++) {
TrieNode* cur = root;
int j = 0, len = nums[i].length();
while (j < len) {
if (nums[i][j] == '0' ) {
if (cur->left == nullptr) {
cur->left = new TrieNode(len - j);
}
else {
cur->left->val
= max(cur->left->val, len - j);
}
cur = cur->left;
}
else {
if (cur->right == nullptr) {
cur->right = new TrieNode(len - j);
}
else {
cur->right->val
= max(cur->right->val, len - j);
}
cur = cur->right;
}
j++;
}
cur->isEnding = true ;
}
return ;
}
int maxDistance(vector<string>& nums)
{
TrieNode* root = new TrieNode(0);
buildTree(root, nums);
int max_distance = 0;
queue<TrieNode*> q;
q.push(root);
while (!q.empty()) {
TrieNode* cur = q.front();
q.pop();
if (cur->left || cur->right) {
if (cur->left && cur->right) {
max_distance
= max(max_distance,
cur->left->val + cur->right->val);
}
else if (cur->isEnding) {
max_distance
= max(max_distance,
cur->left ? cur->left->val
: cur->right->val);
}
}
if (cur->left)
q.push(cur->left);
if (cur->right)
q.push(cur->right);
}
return max_distance;
}
int main()
{
vector<string> nums = { "01011", "010110", "0111" };
int max_distance = maxDistance(nums);
cout << max_distance;
return 0;
}
|
Java
import java.util.LinkedList;
import java.util.Queue;
class TrieNode {
int val;
boolean isEnding;
TrieNode left;
TrieNode right;
TrieNode( int val)
{
this .val = val;
isEnding = false ;
left = right = null ;
}
}
class GFG {
static void buildTree(TrieNode root, String[] nums)
{
for ( int i = 0 ; i < nums.length; i++) {
TrieNode cur = root;
int j = 0 , len = nums[i].length();
while (j < len) {
if (nums[i].charAt(j) == '0' ) {
if (cur.left == null ) {
cur.left = new TrieNode(len - j);
}
else {
cur.left.val = Math.max(
cur.left.val, len - j);
}
cur = cur.left;
}
else {
if (cur.right == null ) {
cur.right = new TrieNode(len - j);
}
else {
cur.right.val = Math.max(
cur.right.val, len - j);
}
cur = cur.right;
}
j++;
}
cur.isEnding = true ;
}
}
static int maxDistance(String[] nums)
{
TrieNode root = new TrieNode( 0 );
buildTree(root, nums);
int max_distance = 0 ;
Queue<TrieNode> q = new LinkedList<>();
q.add(root);
while (!q.isEmpty()) {
TrieNode cur = q.poll();
if (cur.left != null || cur.right != null ) {
if (cur.left != null && cur.right != null ) {
max_distance = Math.max(
max_distance,
cur.left.val + cur.right.val);
}
else if (cur.isEnding) {
max_distance = Math.max(
max_distance, cur.left != null
? cur.left.val
: cur.right.val);
}
}
if (cur.left != null )
q.add(cur.left);
if (cur.right != null )
q.add(cur.right);
}
return max_distance;
}
public static void main(String[] args)
{
String[] nums = { "01011" , "010110" , "0111" };
int max_distance = maxDistance(nums);
System.out.println(max_distance);
}
}
|
Python3
class TrieNode:
def __init__( self , val):
self .val = val
self .isEnding = False
self .left = None
self .right = None
def buildTree(root, nums):
for num in nums:
cur = root
j = 0
length = len (num)
while j < length:
if num[j] = = '0' :
if cur.left is None :
cur.left = TrieNode(length - j)
else :
cur.left.val = max (cur.left.val, length - j)
cur = cur.left
else :
if cur.right is None :
cur.right = TrieNode(length - j)
else :
cur.right.val = max (cur.right.val, length - j)
cur = cur.right
j + = 1
cur.isEnding = True
def maxDistance(nums):
root = TrieNode( 0 )
buildTree(root, nums)
max_distance = 0
queue = []
queue.append(root)
while queue:
cur = queue.pop( 0 )
if cur.left or cur.right:
if cur.left and cur.right:
max_distance = max (max_distance, cur.left.val + cur.right.val)
elif cur.isEnding:
max_distance = max (
max_distance, cur.left.val if cur.left else cur.right.val)
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return max_distance
nums = [ "01011" , "010110" , "0111" ]
max_distance = maxDistance(nums)
print (max_distance)
|
C#
using System;
using System.Collections.Generic;
class TrieNode
{
public int Val { get ; set ; }
public bool IsEnding { get ; set ; }
public TrieNode Left { get ; set ; }
public TrieNode Right { get ; set ; }
public TrieNode( int val)
{
Val = val;
IsEnding = false ;
Left = null ;
Right = null ;
}
}
class Program
{
static void BuildTree(TrieNode root, List< string > nums)
{
foreach ( var num in nums)
{
TrieNode cur = root;
int j = 0, len = num.Length;
while (j < len)
{
if (num[j] == '0' )
{
if (cur.Left == null )
{
cur.Left = new TrieNode(len - j);
}
else
{
cur.Left.Val = Math.Max(cur.Left.Val, len - j);
}
cur = cur.Left;
}
else
{
if (cur.Right == null )
{
cur.Right = new TrieNode(len - j);
}
else
{
cur.Right.Val = Math.Max(cur.Right.Val, len - j);
}
cur = cur.Right;
}
j++;
}
cur.IsEnding = true ;
}
}
static int MaxDistance(List< string > nums)
{
TrieNode root = new TrieNode(0);
BuildTree(root, nums);
int maxDistance = 0;
Queue<TrieNode> queue = new Queue<TrieNode>();
queue.Enqueue(root);
while (queue.Count > 0)
{
TrieNode cur = queue.Dequeue();
if (cur.Left != null || cur.Right != null )
{
if (cur.Left != null && cur.Right != null )
{
maxDistance = Math.Max(maxDistance, cur.Left.Val + cur.Right.Val);
}
else if (cur.IsEnding)
{
maxDistance = Math.Max(maxDistance, cur.Left != null ? cur.Left.Val : cur.Right.Val);
}
}
if (cur.Left != null )
queue.Enqueue(cur.Left);
if (cur.Right != null )
queue.Enqueue(cur.Right);
}
return maxDistance;
}
static void Main()
{
List< string > nums = new List< string > { "01011" , "010110" , "0111" };
int maxDistance = MaxDistance(nums);
Console.WriteLine(maxDistance);
}
}
|
Javascript
class TrieNode {
constructor(val) {
this .val = val;
this .isEnding = false ;
this .left = null ;
this .right = null ;
}
}
function buildTree(root, nums) {
for (let i = 0; i < nums.length; i++) {
let cur = root;
let j = 0, len = nums[i].length;
while (j < len) {
if (nums[i][j] === '0' ) {
if (!cur.left) {
cur.left = new TrieNode(len - j);
} else {
cur.left.val = Math.max(cur.left.val, len - j);
}
cur = cur.left;
} else {
if (!cur.right) {
cur.right = new TrieNode(len - j);
} else {
cur.right.val = Math.max(cur.right.val, len - j);
}
cur = cur.right;
}
j++;
}
cur.isEnding = true ;
}
}
function maxDistance(nums) {
const root = new TrieNode(0);
buildTree(root, nums);
let max_distance = 0;
const queue = [root];
while (queue.length > 0) {
const cur = queue.shift();
if (cur.left || cur.right) {
if (cur.left && cur.right) {
max_distance =
Math.max(max_distance, cur.left.val + cur.right.val);
} else if (cur.isEnding) {
max_distance =
Math.max(max_distance, cur.left ? cur.left.val : cur.right.val);
}
}
if (cur.left) queue.push(cur.left);
if (cur.right) queue.push(cur.right);
}
return max_distance;
}
const nums = [ "01011" , "010110" , "0111" ];
const max_distance = maxDistance(nums);
console.log(max_distance);
|
Time Complexity: O(N * M), where N is the number of binary strings and M is the average length of the binary strings. Auxiliary Space: O(N * M)
|