Longest Substring of A that can be changed to Substring of B in at most T cost


In this problem, we will find the longest substring of A to convert it to a substring of B starting from the same index in less than T cost.

We will use the binary search algorithm to find the maximum length of the substring which follows the given condition. However, the naïve approach to solving the problem is to find all substrings following the conditions in the problem statement and take the substring with maximum length.

Problem statement − We have given a string A and B of length N. Also, we have given a total cost, ‘T’. The K is the cost of converting one character to another.

We need to find the longest substring of the A string such that we can make it the same as a substring starting from the same index in the B string, and the total cost of converting one substring to another should not exceed the T. Also, print the starting and ending index of such substrings.

Sample Examples

Input 

A = "wxyz", B = "wpqt"; K = 2, T = 5;

Output 

Starting index – 0, ending index - 2

Explanation

We can convert the ‘wxy’ to ‘wpq’ with cost 4, which is less than 5.

Input 

A = "wxyz", B = "ewrt"; K = 6, T = 5;

Output 

‘Not possible.’

Explanation

Here, K is greater than T, and no substrings are the same, starting at the same index. So, it is not possible to find the substrings.

Input 

A = "pqdetr", B = "tqcets"; K = 1, T = 5;

Output 

Starting index – 0, ending index - 5

Explanation

We can take string A as a substring as its 5 characters is different, which we can make the same as string B with cost 5.

Approach 1

We will use the binary search algorithm to solve the problem in this approach. We will check whether a valid substring exists of the ‘mid-length. If yes, we will find the valid substring length in the range [mid, string_length]. Otherwise, we will find the valid string length in the [0, mid].

We will use the sliding window technique to find the valid substring of the particular length.

Algorithm

  • Step 1 − Initialize the st_ind and end_ind variables with -1 to store the starting and ending indexes of the maximum length substring.

  • Step 2 − Initialize the ‘left’ pointer with 0 and ‘right’ with the string length + 1. Also, initialize the ‘maxLen’ with 0 to store the maximum length of the substring.

  • Step 3 − Now, we need to use the binary search technique. So, start making iterations using the while loop until the left pointer’s value is less than the right pointer’s.

  • Step 4 − Find the mid-length by dividing the summation of left and right with 2.

  • Step 5 − Execute the isMidValid() function to check whether any substring exists of length equal to the ‘mid-length.

  • Step 5.1 − In the isMidValid() function, initialize the ‘p’ and ‘q’ variables with 0 for the sliding window pointer. Also, initialize the ‘ct’ with 0 to store the cost of the current window to make it the same as string B’s substring.

  • Step 5.2 − Initialize the ‘isValid’ variable with false to track whether a valid substring exists.

  • Step 5.3 − Use the loop to make iterations until ‘q’ is less than string A’s length. In the loop, If A[q] and B[q] are not the same, add K, the cost to convert one character to another to the ‘ct’.

  • Step 5.4 − If the length of the current window is equal to ‘midLen’, follow the steps below.

  • Steps 5.4.1 − If ‘ct’ is less than T, set ‘isValid’ to true, update ‘st_ind’ with p, and ‘end_ind’ with q.

  • Step 5.4.2 − To move to the next window of ‘midLen’ length, remove the cost of ‘A[p]’ from the ‘ct’, and increment ‘p’ value by 1.

  • Step 5.5 − Increment ‘q’ value by 1.

  • Step 5.6 − Return the value of the ‘isValid’ variable.

  • Step 6 − If the function returns true, Update the ‘maxLen’ and search for the maximum length in the right half. Otherwise, search maximum length in the left half.

  • Step 7 − At last, if the value of the ‘st_ind’ is -1, substring is impossible. Otherwise, print the starting and ending index of the longest valid substring.

Example

Following are the programs to the above algorithm −

#include <stdio.h>
#include <string.h>

// Starting and ending position of valid substring
int st_ind = -1, end_ind = -1;

int isMidValid(int midLen, char A[], char B[], int K, int T) {
   int p = 0, q = 0, len = strlen(A), ct = 0;
   // To track whether any substring of length MidLen is valid
   int isValid = 0;
   while (q < len) {
      // Cost for converting one character to another
      ct += (A[q] != B[q]) ? K : 0;
      // Shifting the window to the right
      if (q - p + 1 == midLen) {
         // For cost less than T
         if (ct <= T) {
            isValid = 1;
            st_ind = p;
            end_ind = q;
         }
         // Removing the left character from the window
         ct -= (A[p] != B[p]) ? K : 0;
         p++;
      }
      q++;
   }
   // Output
   return isValid;
}

void printLongestSubstr(char A[], char B[], int K, int T) {
   st_ind = -1, end_ind = -1;

   // Left and right pointers for binary search
   int left = 0;
   int right = strlen(A) + 1;

   // To store the maximum length
   int maxLen = 0;
   while (left < right) {
      // Mid calculation
      int midLen = (left + right) / 2;
      // If midLen length is valid
      if (isMidValid(midLen, A, B, K, T)) {
         // Update max length
         maxLen = midLen;
         // Find the maximum length in the right half
         left = midLen + 1;
      } else {
         // If mid is invalid, then find in the left half
         right = midLen;
      }
   }
   if (st_ind == -1)
      printf("Not possible\n");
   else
      printf("Starting index - %d ending index - %d\n", st_ind, end_ind);
}

int main() {
   char A[] = "wxyz";
   char B[] = "wpqt";
   int K = 2, T = 5;
   printLongestSubstr(A, B, K, T);
   return 0;
}

Output

Starting index - 0 ending index - 2
#include <bits/stdc++.h>
using namespace std;

// Starting and ending position of valid substring
int st_ind = -1, end_ind = -1;
bool isMidValid(int midLen, string &A, string &B, int K, int T) {
   int p = 0, q = 0, len = A.size(), ct = 0;
   // To track whether any substring of length MidLen is valid
   bool isValid = false;
   while (q < len) {
   
      // Cost for converting one character to other
      ct += ((A[q] != B[q]) ? K : 0);
      
      // Shifting the window to right
      if (q - p + 1 == midLen) {
      
         // For cost less than T
         if (ct <= T) {
            isValid = true;
            st_ind = p;
            end_ind = q;
         }
         
         // Removing left character from window
         ct -= ((A[p] != B[p]) ? K : 0);
         p++;
      }
      q++;
   }
   
   // output
   return isValid;
}
void printLongestSubstr(string A, string B, int K, int T) {
   st_ind = -1, end_ind = -1;

   // Left and right pointers for binary search
   int left = 0;
   int right = A.size() + 1;
   int len = A.size();

   // To store the maximum length
   int maxLen = 0;
   while (left < right) {

      // Mid calculation
      int midLen = (left + right) / 2;
      
      // If midLen length is valid
      if (isMidValid(midLen, A, B, K, T)) {
      
         // Update max length
         maxLen = midLen;
         
         // Find the maximum length in the right half
         left = midLen + 1;
      } else {
      
         // If mid is invalid, then find in the left half
         right = midLen;
      }
   }
   if (st_ind == -1)
      cout << "Not possible\n";
   else
      cout << "Starting index - " << st_ind << " ending index - " << end_ind << "\n";
}
int main() {
   string A = "wxyz", B = "wpqt";
   int K = 2, T = 5;
   printLongestSubstr(A, B, K, T);
   return 0;
}

Output

Starting index - 0 ending index - 2
public class LongestValidSubstring {

   // Starting and ending position of valid substring
   static int st_ind = -1;
   static int end_ind = -1;

   public static boolean isMidValid(int midLen, String A, String B, int K, int T) {
      int p = 0;
      int q = 0;
      int len = A.length();
      int ct = 0;
      // To track whether any substring of length MidLen is valid
      boolean isValid = false;
      while (q < len) {
         // Cost for converting one character to other
         ct += (A.charAt(q) != B.charAt(q)) ? K : 0;
         // Shifting the window to the right
         if (q - p + 1 == midLen) {
            // For cost less than T
            if (ct <= T) {
               isValid = true;
               st_ind = p;
               end_ind = q;
            }
            // Removing the left character from the window
            ct -= (A.charAt(p) != B.charAt(p)) ? K : 0;
            p++;
         }
         q++;
      }
      // Output
      return isValid;
   }

   public static void printLongestSubstr(String A, String B, int K, int T) {
      st_ind = -1;
      end_ind = -1;

      // Left and right pointers for binary search
      int left = 0;
      int right = A.length() + 1;

      // To store the maximum length
      int maxLen = 0;
      while (left < right) {
         // Mid calculation
         int midLen = (left + right) / 2;
         // If midLen length is valid
         if (isMidValid(midLen, A, B, K, T)) {
            // Update max length
             maxLen = midLen;
            // Find the maximum length in the right half
            left = midLen + 1;
         } else {
            // If mid is invalid, then find in the left half
            right = midLen;
         }
      }
      if (st_ind == -1) {
         System.out.println("Not possible");
      } else {
         System.out.println("Starting index - " + st_ind + " ending index - " + end_ind);
      }
   }

   public static void main(String[] args) {
      String A = "wxyz";
      String B = "wpqt";
      int K = 2;
      int T = 5;
      printLongestSubstr(A, B, K, T);
   }
}

Output

Starting index - 0 ending index - 2
# Starting and ending position of valid substring
st_ind = -1
end_ind = -1

def is_mid_valid(mid_len, A, B, K, T):
   global st_ind, end_ind
   p = 0
   q = 0
   len_A = len(A)
   ct = 0
   # To track whether any substring of length MidLen is valid
   is_valid = False
   while q < len_A:
      # Cost for converting one character to another
      ct += K if A[q] != B[q] else 0
      # Shifting the window to the right
      if q - p + 1 == mid_len:
         # For cost less than T
         if ct <= T:
            is_valid = True
            st_ind = p
            end_ind = q
         # Removing the left character from the window
         ct -= K if A[p] != B[p] else 0
         p += 1
      q += 1
   # Output
   return is_valid

def print_longest_substr(A, B, K, T):
   global st_ind, end_ind
   st_ind = -1
   end_ind = -1

   # Left and right pointers for binary search
   left = 0
   right = len(A) + 1

   # To store the maximum length
   max_len = 0
   while left < right:
      # Mid calculation
      mid_len = (left + right) // 2
      # If mid_len length is valid
      if is_mid_valid(mid_len, A, B, K, T):
         # Update max length
         max_len = mid_len
         # Find the maximum length in the right half
         left = mid_len + 1
      else:
         # If mid is invalid, then find in the left half
         right = mid_len
   if st_ind == -1:
      print("Not possible")
   else:
      print(f"Starting index - {st_ind} ending index - {end_ind}")

A = "wxyz"
B = "wpqt"
K = 2
T = 5
print_longest_substr(A, B, K, T)

Output

Starting index - 0 ending index - 2

Time complexity – O((logN)*N), where O(N) is for sliding window and O(logN) is for binary search.

Space complexity – O(1), as we don’t use any dynamic space.

Conclusion

We have used the binary search and sliding window, two different algorithms, to solve the single problem. In many cases, we need to use multiple algorithms to solve the problem.

Updated on: 23-Oct-2023

123 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements