Open In App

Find the Longest Substring Conversion

Last Updated : 17 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Given two strings source and target of equal length, and two positive integers, maxCost, and conversionCost, the task is to find the indices of the longest substring in source that can be converted into the same substring in target with a cost less than or equal to maxCost, where each character conversion having a cost of conversionCost units.

Note: If multiple valid substrings exist, return any one of them.

Examples:

Input: source = “abcd”, target = “bcdf”, conversionCost = 1, maxCost = 3
Output: 0 2
Explanation: The substring of source from index 0 to 2 is “abc” which can change to “bcd” in target. The cost of changing would be 3 <= maxCost. And the maximum length possible is 3.

Input: source = “adcf”, target = “cdef”, conversionCost = 3, maxCost = 5
Output: 1 3

Finding Longest Substring Conversion using Binary Search:

The idea is to use binary search on answer to find the maximum possible length, and for each length, check its possible to change within maxCost and based on that update the search space of answer and keep track of indices of start and end position of valid substring.

Step-by-step approach:

  • Initialize low to 1 and high to the string’s length.
  • Initialize result to store the maximum length of a valid substring.
  • While low is less than high, do the following:
    • Calculate mid = (start + end) / 2
    • Check if mid is a possible length for a valid substring.
    • If valid, update result to mid and shift low to mid + 1.
    • Otherwise, shift high to mid.
  • If a valid substring is found, print its starting and ending indices.

Below is the implementation of the above approach.

C++




#include <bits/stdc++.h>
using namespace std;
 
// Initilise source variable startPos
// and endPos for storing the starting
// and ending position of valid
// substring respectively.
int startPos = -1, endPos = -1;
 
// Function to check if a substring
// of a given length is a
// valid substring.
bool isValid(int len, string& s, string& t,
             int conversionCost, int maxCost)
{
    int start = 0, end = 0, n = s.size();
    int currCost = 0;
 
    while (end < n) {
 
        // Increment the current
        // cost if characters are
        // different.
        if (s[end] != t[end]) {
            currCost += conversionCost;
        }
 
        // If the substring length matches
        // the given length.
        if (end - start + 1 == len) {
            // Check if the cost is within
            // the maximum cost.
            if (currCost <= maxCost) {
                // Update the starting position
                // of the valid substring.
                startPos = start;
 
                // Update the ending position
                // of the valid substring.
                endPos = end;
 
                // Return true as this is a
                // valid substring.
                return true;
            }
 
            // Subtract the cost
            // if the first
            // character of the
            // previous substring
            // was different.
            if (s[start] != t[start]) {
                currCost -= conversionCost;
            }
 
            // Move the start of the substring.
            start++;
 
            // Move the end of the substring.
            end++;
        }
 
        // Increment the end position of the
        // substring.
        else {
            end++;
        }
    }
 
    // If no valid substring is found,
    // return false.
    return false;
}
 
void validSubstring(string source, string target,
                    int conversionCost, int maxCost)
{
 
    // Initilise source variable low
    // with minimum valid length
    // substring possible.
    int low = 1;
 
    // Initilise source variable high
    // with maximum valid length
    // substring possible.
    int high = source.size();
 
    // Do while low is less
    // than equal to high
    while (low <= high) {
 
        // Calculate the mid
        int mid = (low + high) / 2;
 
        // Check if mid is possible
        // length for valid substring
        if (isValid(mid, source, target, conversionCost,
                    maxCost)) {
 
            // Shift low to mid + 1
            low = mid + 1;
        }
 
        // Otherwise shift high
        // to mid - 1
        else {
            high = mid - 1;
        }
    }
 
    if (startPos == -1)
        cout << "Not possible\n";
    else
        cout << startPos << " " << endPos << "\n";
}
 
// Driver code
int main()
{
 
    // First test case
    string source = "adcf", target = "cdef";
    int conversionCost = 3, maxCost = 5;
 
    // Function Call
    validSubstring(source, target, conversionCost, maxCost);
 
    return 0;
}


Java




// Java code for the above approach
 
class GFG {
    // Initilise source variable startPos
    // and endPos for storing the starting
    // and ending position of valid
    // substring respectively.
    static int startPos = -1, endPos = -1;
 
    // Function to check if a substring
    // of a given length is a
    // valid substring.
    static boolean isValid(int len, String s, String t,
                           int conversionCost, int maxCost)
    {
        int start = 0, end = 0, n = s.length();
        int currCost = 0;
 
        while (end < n) {
 
            // Increment the current
            // cost if characters are
            // different.
            if (s.charAt(end) != t.charAt(end)) {
                currCost += conversionCost;
            }
 
            // If the substring length matches
            // the given length.
            if (end - start + 1 == len) {
                // Check if the cost is within
                // the maximum cost.
                if (currCost <= maxCost) {
                    // Update the starting position
                    // of the valid substring.
                    startPos = start;
 
                    // Update the ending position
                    // of the valid substring.
                    endPos = end;
 
                    // Return true as this is a
                    // valid substring.
                    return true;
                }
 
                // Subtract the cost
                // if the first
                // character of the
                // previous substring
                // was different.
                if (s.charAt(start) != t.charAt(start)) {
                    currCost -= conversionCost;
                }
 
                // Move the start of the substring.
                start++;
 
                // Move the end of the substring.
                end++;
            }
 
            // Increment the end position of the
            // substring.
            else {
                end++;
            }
        }
 
        // If no valid substring is found,
        // return false.
        return false;
    }
 
    static void validSubstring(String source, String target,
                               int conversionCost,
                               int maxCost)
    {
 
        // Initilise source variable low
        // with minimum valid length
        // substring possible.
        int low = 1;
 
        // Initilise source variable high
        // with maximum valid length
        // substring possible.
        int high = source.length();
 
        // Do while low is less
        // than equal to high
        while (low <= high) {
 
            // Calculate the mid
            int mid = (low + high) / 2;
 
            // Check if mid is possible
            // length for valid substring
            if (isValid(mid, source, target, conversionCost,
                        maxCost)) {
 
                // Shift low to mid + 1
                low = mid + 1;
            }
 
            // Otherwise shift high
            // to mid - 1
            else {
                high = mid - 1;
            }
        }
 
        if (startPos == -1)
            System.out.println("Not possible\n");
        else
            System.out.println(startPos + " " + endPos
                               + "\n");
    }
 
    // Driver code
    public static void main(String[] args)
    {
        // First test case
        String source = "adcf", target = "cdef";
        int conversionCost = 3, maxCost = 5;
 
        // Function Call
        validSubstring(source, target, conversionCost,
                       maxCost);
    }
}
 
// This code is contributed by ragul21


Python3




def is_valid(length, s, t, conversion_cost, max_cost):
    global start_pos, end_pos
    start, end, n = 0, 0, len(s)
    curr_cost = 0
 
    while end < n:
        # Increment the current cost if characters are different.
        if s[end] != t[end]:
            curr_cost += conversion_cost
 
        if end - start + 1 == length:
            # Check if the cost is within the maximum cost.
            if curr_cost <= max_cost:
                # Update the starting position of the valid substring.
                start_pos = start
                # Update the ending position of the valid substring.
                end_pos = end
                # Return true as this is a valid substring.
                return True
 
            # Subtract the cost if the first character
            # of the previous substring was different.
            if s[start] != t[start]:
                curr_cost -= conversion_cost
 
            # Move the start of the substring.
            start += 1
            # Move the end of the substring.
            end += 1
        else:
            # Increment the end position of the substring.
            end += 1
 
    # If no valid substring is found, return false.
    return False
 
 
def valid_substring(source, target, conversion_cost, max_cost):
    global start_pos, end_pos
    # Initialize source variable low with the
    # minimum valid length substring possible.
    low = 1
    # Initialize source variable high with the
    # maximum valid length substring possible.
    high = len(source)
 
    # Do while low is less than equal to high
    while low <= high:
        # Calculate the mid
        mid = (low + high) // 2
 
        # Check if mid is a possible length for a valid substring
        if is_valid(mid, source, target, conversion_cost, max_cost):
            # Shift low to mid + 1
            low = mid + 1
        else:
            # Otherwise shift high to mid - 1
            high = mid - 1
 
    if start_pos == -1:
        print("Not possible")
    else:
        print(f"{start_pos} {end_pos}")
 
 
# Driver code
source_str = "adcf"
target_str = "cdef"
 
# Function Call
conversion_cost_val = 3
max_cost_val = 5
start_pos, end_pos = -1, -1
valid_substring(source_str, target_str, conversion_cost_val, max_cost_val)


C#




// C# code for the above approach
 
using System;
 
class GFG
{
    // Initialize source variable startPos
    // and endPos for storing the starting
    // and ending position of valid
    // substring respectively.
    static int startPos = -1, endPos = -1;
 
    // Function to check if a substring
    // of a given length is a
    // valid substring.
    static bool IsValid(int len, string s, string t,
                         int conversionCost, int maxCost)
    {
        int start = 0, end = 0, n = s.Length;
        int currCost = 0;
 
        while (end < n)
        {
            // Increment the current
            // cost if characters are
            // different.
            if (s[end] != t[end])
            {
                currCost += conversionCost;
            }
 
            // If the substring length matches
            // the given length.
            if (end - start + 1 == len)
            {
                // Check if the cost is within
                // the maximum cost.
                if (currCost <= maxCost)
                {
                    // Update the starting position
                    // of the valid substring.
                    startPos = start;
 
                    // Update the ending position
                    // of the valid substring.
                    endPos = end;
 
                    // Return true as this is a
                    // valid substring.
                    return true;
                }
 
                // Subtract the cost
                // if the first
                // character of the
                // previous substring
                // was different.
                if (s[start] != t[start])
                {
                    currCost -= conversionCost;
                }
 
                // Move the start of the substring.
                start++;
 
                // Move the end of the substring.
                end++;
            }
 
            // Increment the end position of the
            // substring.
            else
            {
                end++;
            }
        }
 
        // If no valid substring is found,
        // return false.
        return false;
    }
 
    static void ValidSubstring(string source, string target,
                               int conversionCost,
                               int maxCost)
    {
        // Initialize source variable low
        // with minimum valid length
        // substring possible.
        int low = 1;
 
        // Initialize source variable high
        // with maximum valid length
        // substring possible.
        int high = source.Length;
 
        // Do while low is less
        // than equal to high
        while (low <= high)
        {
            // Calculate the mid
            int mid = (low + high) / 2;
 
            // Check if mid is possible
            // length for valid substring
            if (IsValid(mid, source, target, conversionCost,
                        maxCost))
            {
                // Shift low to mid + 1
                low = mid + 1;
            }
 
            // Otherwise shift high
            // to mid - 1
            else
            {
                high = mid - 1;
            }
        }
 
        if (startPos == -1)
            Console.WriteLine("Not possible\n");
        else
            Console.WriteLine(startPos + " " + endPos
                               + "\n");
    }
 
    // Driver code
    public static void Main(string[] args)
    {
        // First test case
        string source = "adcf", target = "cdef";
        int conversionCost = 3, maxCost = 5;
 
        // Function Call
        ValidSubstring(source, target, conversionCost,
                       maxCost);
    }
}
// This code is contributed by uttamdp_10


Javascript




//Javascript code for the above approach
 
// Initilise source variable startPos
// and endPos for storing the starting
// and ending position of valid
// substring respectively.
let startPos = -1, endPos = -1;
 
// Function to check if a substring
// of a given length is a
// valid substring.
function isValid(len, s, t, conversionCost, maxCost) {
    let start = 0, end = 0, n = s.length;
    let currCost = 0;
 
    while (end < n) {
        // Increment the current
        // cost if characters are
        // different.
        if (s[end] !== t[end]) {
            currCost += conversionCost;
        }
 
        // If the substring length matches
        // the given length.
        if (end - start + 1 === len) {
            // Check if the cost is within
            // the maximum cost.
            if (currCost <= maxCost) {
                // Update the starting position
                // of the valid substring.
                startPos = start;
                // Update the ending position
                // of the valid substring.
                endPos = end;
                // Return true as this is a
                // valid substring.
                return true;
            }
 
            // Subtract the cost
            // if the first
            // character of the
            // previous substring
            // was different.
            if (s[start] !== t[start]) {
                currCost -= conversionCost;
            }
 
            // Move the start of the substring.
            start++;
            // Move the end of the substring.
            end++;
        }
        // Increment the end position of the
        // substring.
        else {
            end++;
        }
    }
 
    // If no valid substring is found,
    // return false.
    return false;
}
 
function validSubstring(source, target, conversionCost, maxCost) {
    // Initilise source variable low
    // with minimum valid length
    // substring possible.
    let low = 1;
    // Initilise source variable high
    // with maximum valid length
    // substring possible.
    let high = source.length;
 
    // Do while low is less
    // than equal to high
    while (low <= high) {
        // Calculate the mid
        let mid = Math.floor((low + high) / 2);
 
        // Check if mid is possible
        // length for valid substring
        if (isValid(mid, source, target, conversionCost, maxCost)) {
            // Shift low to mid + 1
            low = mid + 1;
        } else {
            // Otherwise shift high
            // to mid - 1
            high = mid - 1;
        }
    }
 
    if (startPos === -1)
        console.log("Not possible");
    else
        console.log(startPos + " " + endPos);
}
 
// Driver code
 
// First test case
let source = "adcf", target = "cdef";
// Function Call
let conversionCost = 3, maxCost = 5;
 
validSubstring(source, target, conversionCost, maxCost);


Output

1 3







Time Complexity: O(N* log(N))
Auxiliary Space: O(1)



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads