Maximize value of Binary String in K steps by performing XOR of Substrings


In this problem, we will maximize the value of the binary string by performing K XOR operations of substrings of the given binary string.

To maximize any binary string, we should maximize the substring starting from the leftmost zero. For example, to maximize the ‘11001’ string, we need to choose another substring in such a way that we can maximize the ‘001’ substring.

Problem Statement

We have given a binary string named bin_str containing N characters. We have to maximize the value of the binary string in K operations by taking the XOR operation of any two substrings. It is given that substrings can be the same, intersecting or non-intersecting.

Sample Examples

Input 

bin_str = "1101"; K = 1;

Output 

1111

Explanation

We can take 10 and 1101 substrings, and when we perform XOR of both, we get the 1111 maximum string.

Input 

bin_str = "110101"; K = 2

Output 

111110

Explanation

  • In the first operation, we can take 110101 and 1010 substrings. Whesubstringrm XOR operation of both strings, we get 111111 binary string.

  • In the second operation, we can take 111111 and 1 substring, and when we perform the XOR operation of both, we get 111110, the maximum string we can get.

Input 

bin_str = "01"; K = 1;

Output 

1

Explanation

Take 01 and 0 substrings to get 1.

Approach 1

In this approach, we will take a substring from the leftmost 0 to the end and find another substring of the string to get the maximum binary string value.

For example, the binary string is 1110010101. To maximize the binary string, we need to maximize the 0010101 substrings. So, we will take the binary string itself as one substring and another string of the same length, ‘0010101,’ to maximize the binary string.

Algorithm

  • Step 1 − Execute the maxValUtil() function for K times, and update the binary string with its returned value.

  • Step 2 − In the maxValUtil() function, Initialize the ‘leftZero’ with -1 to store the index of the leftmost zero, ‘cnt0’ and ‘cnt1’ with 0 to store the count of 0 and 1 in the binary string, respectively.

  • Step 3 − Traverse the string, and if the current character is ‘1’, increment the ‘cnt1’ by 1. Otherwise, if ‘leftZero’ is -1, update its value with the current index and increment the ‘cnt0’ value.

  • Step 4 − If ‘cnt1’ and ‘len’ is equal, take the XOR of a binary string with ‘1’ and return its value.

  • Step 4.1 − Take the length of both strings in the getXOR() function. If both strings are not of the same length, add the zeros to the string with the smallest length by executing the addZeros() function.

  • Step 4.1.1 − In the addZero() function, append the required zeros at the start of the string.

  • Step 4.2 − Initialize the ‘XOR” string to store the result after performing the XOR operation of both strings.

  • Step 4.3 − Traverse both strings and if the character at the pth index in both strings is the same, append ‘0’ to the XOR string. Otherwise, append ‘1’ to the XOR string.

  • Step 4.4 − Return the XOR string.

  • Step 5 − In the maxValUtil() function, if ‘cnt0’ is equal to the binary string’s length, return ‘0’.

  • Step 6 − Initialize the ‘rightStr’ string with the substring starting from the ‘leftZero’ index using the substr() method. Also, initialize the ‘size’ with the ‘rightStr’ string’s size, temp with the ‘rightStr’ string, ‘maxRes’, ‘temp1’, and ‘temp2’ with an empty string.

  • Step 7 − Start traversing the binary string. If the index is less than the ‘size’ variable’s value, append a character to the ‘temp1’ string.

  • Step 8 − Else, Get the XOR of the ‘temp’ and ‘temp1’ strings. If the XOR value exceeds the ‘maxRes’ string’s value, update the ‘maxRes’ with ‘res’ and ‘temp2’ with ‘temp1’. Also, remove the first character from the ‘temp1’ string and append the current character at last.

Here, we find the ‘temp2’ substring such that the XOR of ‘temp1’ and ‘temp2’ becomes maximum to maximize the binary string.

  • Step 9 − Handle the last case in which we take XOR of temp1 string with rightStr string.

  • SStep 10 − Next, take the XOR of the binary string and temp2 string, and store the result in the answer.

  • Step 11 − Return the ‘answer’ string after removing the leading zeros.

Example

Following are the Programs to the above algorithm −

#include <stdio.h>
#include <string.h>
#include <stdlib.h> // Added for dynamic memory allocation

// Function to add 'n' zeros to the beginning of a string
void addNZero(char *substr, int n) {
   int i;

   // Shift existing characters to the right to make space for zeros
   for (i = strlen(substr); i >= 0; i--) {
      substr[i + n] = substr[i];
   }

   // Add 'n' zeros at the beginning
   for (i = 0; i < n; i++) {
      substr[i] = '0';
   }
}

// Function to perform XOR of two strings
void getXOR(char *temp1, char *temp2, char *result) {
   int len1 = strlen(temp1);
   int len2 = strlen(temp2);
   int len = len1 > len2 ? len1 : len2; // Maximum length
   int i;

   // Make both strings of equal length by adding leading zeros
   if (len1 > len2) {
      addNZero(temp2, len1 - len2);
   } else if (len2 > len1) {
      addNZero(temp1, len2 - len1);
   }

   // Compute XOR
   for (i = 0; i < len; i++) {
      if (temp1[i] == temp2[i]) {
         result[i] = '0';
      } else {
         result[i] = '1';
      }
   }

   // Null-terminate the result string
   result[len] = '\0';
}

// Function to find the maximum value of a binary string after K XOR operations
void findMaxValue(char *bin_str, int K) {
   int len = strlen(bin_str);
   int leftZero = -1, cnt0 = 0, cnt1 = 0;
   char *rightStr, *temp, *maxRes, *temp1, *temp2;
   int size;

   // Calculate the number of 0's and 1's in the binary string
   for (int p = 0; p < len; p++) {
      if (bin_str[p] == '1') {
         cnt1++;
      } else {
         if (leftZero == -1) {
            leftZero = p;
         }
         cnt0++;
      }
   }

   // Case 1 - When the string contains all 1's
   if (cnt1 == len) {
      char one[] = "1";
      getXOR(bin_str, one, bin_str);
      return;
   }

   // Case 2 - When the string contains all zeros
   if (cnt0 == len) {
      printf("0\n");
      return;
   }

   // Take the substring starting from the leftmost '0' to maximize it
   rightStr = bin_str + leftZero;
   size = len - leftZero;
   temp = rightStr;
   maxRes = (char *)malloc((len + 1) * sizeof(char)); // Allocate memory for maxRes
   temp1 = (char *)malloc((len + 1) * sizeof(char));   // Allocate memory for temp1
   temp2 = (char *)malloc((len + 1) * sizeof(char));   // Allocate memory for temp2

   // Initialize memory to avoid undefined behavior
   memset(maxRes, 0, (len + 1) * sizeof(char));
   memset(temp1, 0, (len + 1) * sizeof(char));
   memset(temp2, 0, (len + 1) * sizeof(char));

   // Choosing the second string
   for (int q = 0; q < len; q++) {
      if (q < size) {
         temp1[q] = bin_str[q];
      } else {
         // If temp1 gives the maximum XOR result, choose it as the second string
         char res[len + 1];
         getXOR(temp, temp1, res);
         if (strcmp(res, maxRes) > 0) {
            strcpy(maxRes, res);
            strcpy(temp2, temp1);
         }

         // Update temp1 string
         for (int i = 0; i < size - 1; i++) {
            temp1[i] = temp1[i + 1];
         }
         temp1[size - 1] = bin_str[q];
      }
   }

   // Handling the last case
   char res[len + 1];
   getXOR(temp1, temp, res);
   if (strcmp(res, maxRes) > 0) {
      strcpy(maxRes, res);
      strcpy(temp2, rightStr);
   }

   // Take the XOR of the original string and the second string
   getXOR(bin_str, temp2, bin_str);

   // Remove leading zeros
   leftZero = -1;
   for (int p = 0; p < len; p++) {
      if (bin_str[p] != '0') {
         leftZero = p;
         break;
      }
   }
   if (leftZero == -1) {
      printf("0\n");
   } else {
      printf("%s\n", bin_str + leftZero);
   }

   // Free dynamically allocated memory
   free(maxRes);
   free(temp1);
   free(temp2);
}

int main() {
   char bin_str[] = "1101";
   int K = 1;
   printf("The maximum value of the string after performing 1 XOR operations is - ");
   findMaxValue(bin_str, K);
   return 0;
}

Output

The maximum value of the string after performing 1 XOR operations is - 1111
#include <bits/stdc++.h>
using namespace std;

void addNZero(string &substr, int n) {
   // Adding the initial '0' to the string to make its length the same as the other sub string
   for (int p = 0; p < n; p++) {
      substr = "0" + substr;
   }
}

// Finding XOR of two strings
string getXOR(string temp1, string temp2) {  

   // Get string sizes
   int temp1_len = temp1.length();
   int temp2_len = temp2.length();
   
   // Append zeros to the smaller string
   if (temp1_len > temp2_len) {
      addNZero(temp2, temp1_len - temp2_len);
   } else if (temp2_len > temp1_len) {
      addNZero(temp1, temp2_len - temp1_len);
   }
   
   // Final string length
   int len = max(temp1_len, temp2_len);
   
   // To store the resultant XOR
   string XOR = "";
   
   // Take XOR of both strings
   for (int p = 0; p < len; p++) {
      if (temp1[p] == temp2[p])
         XOR += "0";
      else
         XOR += "1";
   }
   return XOR;
}
string maxValUtil(string bin_str) {

   // String length
   int len = bin_str.size();
   int leftZero = -1, cnt0 = 0, cnt1 = 0;
   
   // Calculate number of 0's and 1's in the given string.
   for (int p = 0; p < len; p++) {
      if (bin_str[p] == '1') {
         cnt1++;
      } else {
      
         // For the left most '0'
         if (leftZero == -1) {
            leftZero = p;
         }
         cnt0++;
      }
   }
   
   // Case 1 - When the string contains all 1's
   if (cnt1 == len) {
      return getXOR(bin_str, "1");
   }
   
   // Case 2 - When the string contains all zeros
   if (cnt0 == len) {
      return "0";
   }
   
   // Take the substring starting from left most '0' as we need to maximize it
   string rightStr = bin_str.substr(leftZero, len - leftZero);
   int size = rightStr.size();
   string temp = rightStr;
   string maxRes = "";
   string temp1 = "", temp2 = "";
   
   // Choosing the second string
   for (int q = 0; q < len; q++) {
   
      // Finding the substring of length 'size' from start
      if (q < size) {
      temp1 += bin_str[q];
      } else {
      
         // If temp1 gives the maximum XOR result, choose it as a second string
         string res = getXOR(temp, temp1);
         if (res > maxRes) {
            maxRes = res;
            temp2 = temp1;
         }
         
         // Update temp1 string
         temp1 = temp1.substr(1);
         temp1 += bin_str[q];
      }
   }
   
   // Handling the last case
   string res = getXOR(temp1, temp);
   if (res > maxRes) {
      maxRes = res;
      temp2 = rightStr;
   }
   
   // Take the XOR of the original string and the second string
   string answer = getXOR(bin_str, temp2);
   leftZero = -1;
   for (int p = 0; p < answer.size(); p++) {
   
      // Remove initial zeros
      if (answer[p] != '0') {
         leftZero = p;
         break;
      }
   }
   if (leftZero == -1) {
      return "0";
   }
   
   // Final maximum string
   return answer.substr(leftZero);
}
string findMaxValue(string bin_str, int K) {

   // Find the maximum value of the updated binary string
   for (int p = 0; p < K; p++) {
      bin_str = maxValUtil(bin_str);
   }
   return bin_str;
}
int main() {
   string bin_str = "1101";
   int K = 1;
   cout << "The maximum value of the string after performing " << K << " XOR operations is - " << findMaxValue(bin_str, K) << endl;
   return 0;
}

Output

The maximum value of the string after performing 1 XOR operations is - 1111
public class Main {
   // Function to calculate XOR of two strings
   public static String getXOR(String temp1, String temp2) {
      int len1 = temp1.length();
      int len2 = temp2.length();
      int length = Math.max(len1, len2);

      // Add leading zeros to the shorter string
      if (len1 > len2) {
         temp2 = "0".repeat(len1 - len2) + temp2;
      } else if (len2 > len1) {
         temp1 = "0".repeat(len2 - len1) + temp1;
      }

      StringBuilder XOR = new StringBuilder();

      // Perform XOR of both strings
      for (int i = 0; i < length; i++) {
         XOR.append(temp1.charAt(i) == temp2.charAt(i) ? '0' : '1');
      }

      return XOR.toString();
   }

   // Function to find the maximum value substring
   public static String maxValUtil(String bin_str) {
      int length = bin_str.length();
      int leftZero = -1;
      int cnt0 = 0, cnt1 = 0;

      // Count the number of 0's and 1's in the binary string
      for (int i = 0; i < length; i++) {
         if (bin_str.charAt(i) == '1') {
            cnt1++;
         } else {
            if (leftZero == -1) {
               leftZero = i;
            }
            cnt0++;
         }
      }

      // Case 1: All 1's in the string
      if (cnt1 == length) {
         return getXOR(bin_str, "1");
      }

      // Case 2: All 0's in the string
      if (cnt0 == length) {
         return "0";
      }

      // Find the substring starting from the leftmost '0'
      String rightStr = bin_str.substring(leftZero);
      int size = rightStr.length();
      String temp = rightStr;
      String maxRes = "";
      String temp1 = "";
      String temp2 = "";

      // Choosing the second string
      for (int i = 0; i < length; i++) {
         if (i < size) {
            temp1 += bin_str.charAt(i);
         } else {
            String res = getXOR(temp, temp1);
            if (res.compareTo(maxRes) > 0) {
               maxRes = res;
               temp2 = temp1;
            }
            temp1 = temp1.substring(1) + bin_str.charAt(i);
         }
      }

      // Handling the last case
      String res = getXOR(temp1, temp);
      if (res.compareTo(maxRes) > 0) {
         maxRes = res;
         temp2 = rightStr;
      }

      // Take the XOR of the original string and the second string
      String answer = getXOR(bin_str, temp2);
      leftZero = -1;

      // Remove leading zeros
      for (int i = 0; i < answer.length(); i++) {
         if (answer.charAt(i) != '0') {
            leftZero = i;
            break;
         }
      }

      if (leftZero == -1) {
         return "0";
      }

      // Final maximum string
      return answer.substring(leftZero);
   }

   // Function to find the maximum value of the binary string after K XOR operations
   public static String findMaxValue(String bin_str, int K) {
      for (int i = 0; i < K; i++) {
         bin_str = maxValUtil(bin_str);
      }
      return bin_str;
   }

   public static void main(String[] args) {
      String bin_str = "1101";
      int K = 1;
      String result = findMaxValue(bin_str, K);
      System.out.println("The maximum value of the string after performing " + K + " XOR operations is - " + result);
   }
}

Output

The maximum value of the string after performing 1 XOR operations is - 1111
def addNZero(substr, n):
   for _ in range(n):
      substr = '0' + substr

# Finding XOR of two strings
def getXOR(temp1, temp2):
   # Get string sizes
   temp1_len = len(temp1)
   temp2_len = len(temp2)

   # Append zeros to the smaller string
   if temp1_len > temp2_len:
      temp2 = '0' * (temp1_len - temp2_len) + temp2
   elif temp2_len > temp1_len:
      temp1 = '0' * (temp2_len - temp1_len) + temp1

   # Final string length
   length = max(temp1_len, temp2_len)

   # Take XOR of both strings
   result = ''
   for p in range(length):
      if temp1[p] == temp2[p]:
         result += '0'
      else:
         result += '1'
   return result

def maxValUtil(bin_str):
   # String length
   length = len(bin_str)
   leftZero = -1
   cnt0 = 0
   cnt1 = 0

   # Calculate the number of 0's and 1's in the given string.
   for p in range(length):
      if bin_str[p] == '1':
         cnt1 += 1
      else:
         # For the leftmost '0'
         if leftZero == -1:
            leftZero = p
         cnt0 += 1

   # Case 1 - When the string contains all 1's
   if cnt1 == length:
      return getXOR(bin_str, '1')

   # Case 2 - When the string contains all zeros
   if cnt0 == length:
      return '0'

   # Take the substring starting from the leftmost '0' as we need to maximize it
   rightStr = bin_str[leftZero:]
   size = len(rightStr)
   temp = rightStr
   maxRes = ''
   temp1 = ''
   temp2 = ''

   # Choosing the second string
   for q in range(length):
      # Finding the substring of length 'size' from start
      if q < size:
         temp1 += bin_str[q]
      else:
         # If temp1 gives the maximum XOR result, choose it as the second string
         res = getXOR(temp, temp1)
         if res > maxRes:
            maxRes = res
            temp2 = temp1

         # Update temp1 string
         temp1 = temp1[1:] + bin_str[q]

   # Handling the last case
   res = getXOR(temp1, temp)
   if res > maxRes:
      maxRes = res
      temp2 = rightStr

   # Take the XOR of the original string and the second string
   answer = getXOR(bin_str, temp2)
   leftZero = -1
   for p in range(len(answer)):
      # Remove initial zeros
      if answer[p] != '0':
         leftZero = p
         break
   if leftZero == -1:
      return '0'

   # Final maximum string
   return answer[leftZero:]

def findMaxValue(bin_str, K):
   # Find the maximum value of the updated binary string
   for _ in range(K):
      bin_str = maxValUtil(bin_str)
   return bin_str

bin_str = '1101'
K = 1
result = findMaxValue(bin_str, K)
print(f"The maximum value of the string after performing {K} XOR operations is - {result}")

Output

The maximum value of the string after performing 1 XOR operations is - 1111

Time complexity – O(N*N*K), where O(N) is for finding substring to maximize binary string, another O(N) is to perform the XOR operation of two strings, and O(K) is to perform total K operations.

Space complexity – O(N) to store the temporary strings.

Updated on: 23-Oct-2023

142 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements