Given two strings s1 and s2 of the same length, which consist of lowercase letters and also an integer k. The task is to find the maximum length up to which s1 can be changed to s2 within the given cost k.
The cost of changing a character is given by the absolute difference between the ASCII value of the characters. That is, to change a character at index i, cost = |s1[i] - s2[i]|
Examples:
Input: s1 = abcd, s2 = bcde, k = 3
Output: 3
Explanation: The first three characters can be changed with cost = 1 + 1 + 1.Input: s1 = "xyzabcd", s2 = "bcdfxyw", k = 5
Output: 4
Explanation : abcd can be changed to match bcdf because the total cost to change these characters is 1 + 1 + 1 + 2 = 5, which is within k.Input: s1 = "abcd", s2 = "cdef", k = 3
Output: 1
Explanation: A maximum of 1 character can be changed because the cost to change each character is 2, and taking more than one character would exceed the total cost K.
Table of Content
[Better Approach] Using Prefix Sum + Two Pointers – O(n) Time and O(n) Space
This approach uses a prefix sum array to store the cumulative cost of converting
s1tos2. Then, using a two-pointer technique, we find the longest substring whose cost does not exceedk.
The prefix array helps in calculating the cost of any substring in O(1) time.
- Maintain two pointers, say i and j.
- In a while loop, check if the difference between ith index and jth index of prefix array is greater than given cost or not.
- If the difference is greater than the given cost, then increase the j pointer to compensate for the cost, else increase the i pointer.
Below is the implementation of the above approach:
#include <bits/stdc++.h>
using namespace std;
// Function to find the maximum length
int maxLen(string s1, string s2, int K)
{
int n = s1.size();
vector<int> prefix(n + 1, 0);
int sol = 0;
// Build prefix sum of cost
for (int i = 1; i <= n; i++) {
prefix[i] = prefix[i - 1] + abs(s1[i - 1] - s2[i - 1]);
}
int j = 0;
for (int i = 1; i <= n; i++) {
while ((prefix[i] - prefix[j]) > K) {
j++;
}
sol = max(sol, i - j);
}
return sol;
}
// Driver code
int main()
{
string s1 = "abcd";
string s2 = "bcde";
int K = 3;
cout << maxLen(s1, s2, K) << "\n";
return 0;
}
class GFG
{
// Function to find the maximum length
static int maxLen(String s1, String s2, int K)
{
int n = s1.length();
int[] prefix = new int[n + 1];
int sol = 0;
// Build prefix cost array
for (int i = 1; i <= n; i++)
{
prefix[i] = prefix[i - 1] +
Math.abs(s1.charAt(i - 1) - s2.charAt(i - 1));
}
int j = 0;
for (int i = 1; i <= n; i++)
{
while ((prefix[i] - prefix[j]) > K)
{
j++;
}
// Update maximum length
sol = Math.max(sol, i - j);
}
return sol;
}
// Driver code
public static void main(String[] args)
{
String s1 = "abcd", s2 = "bcde";
int K = 3;
System.out.print(maxLen(s1, s2, K));
}
}
# Function to find the maximum length
def maxLen(s1, s2, K):
n = len(s1)
prefix = [0] * (n + 1)
sol = 0
# Build prefix cost array
for i in range(1, n + 1):
prefix[i] = prefix[i - 1] + abs(ord(s1[i - 1]) - ord(s2[i - 1]))
j = 0
for i in range(1, n + 1):
while (prefix[i] - prefix[j]) > K:
j += 1
sol = max(sol, i - j)
return sol
# Driver code
s1 = "abcd"
s2 = "bcde"
K = 3
print(maxLen(s1, s2, K))
// C# program to find the
// maximum length of equal subString
// within a given cost
using System;
class GFG
{
// Function to find the maximum length
static int maxLen(string X, string Y,
int N, int K)
{
int []count = new int[N + 1];
int sol = 0;
count[0] = 0;
// Fill the prefix array with
// the difference of letters
for (int i = 1; i <= N; i++)
{
count[i] = count[i - 1] +
Math.Abs(X[i - 1] -
Y[i - 1]);
}
int j = 0;
for (int i = 1; i <= N; i++)
{
while ((count[i] - count[j]) > K)
{
j++;
}
// Update the maximum length
sol = Math.Max(sol, i - j);
}
return sol;
}
// Driver code
public static void Main()
{
int N = 4;
string X = "abcd", Y = "bcde";
int K = 3;
Console.WriteLine(maxLen(X, Y, N, K) + "\n");
}
}
// Function to find the maximum length
function maxLen(s1, s2, K)
{
let n = s1.length;
let prefix = new Array(n + 1).fill(0);
let sol = 0;
for (let i = 1; i <= n; i++)
{
prefix[i] = prefix[i - 1] +
Math.abs(s1[i - 1].charCodeAt(0) -
s2[i - 1].charCodeAt(0));
}
let j = 0;
for (let i = 1; i <= n; i++)
{
while ((prefix[i] - prefix[j]) > K)
{
j++;
}
sol = Math.max(sol, i - j);
}
return sol;
}
// Driver code
let s1 = "abcd";
let s2 = "bcde";
let K = 3;
console.log(maxLen(s1, s2, K));
Output
3
Time Complexity: O(n)
Auxiliary Space: O(n), where n is the length of the given string.
[Expected Approach] Using Sliding Window – O(n) Time and O(1) Space
This approach uses the sliding window technique to find the maximum length of a substring such that the total cost of converting
s1tos2does not exceedk. We maintain a window with two pointers and keep track of the current cost. If the cost exceeds k, we shrink the window from the left until it becomes valid again
- We maintain a sliding window of length len that starts at index 0 and ends at index i.
- We calculate the total cost of changing the characters within this window and compare it with the given cost k.
- If the total cost is less than or equal to k, we update the maximum length seen so far. If the total cost is greater than k, we shrink the window from the left to decrease the cost until it becomes less than or equal to k.
- To calculate the cost of changing the characters at each index i, we use the absolute difference between the ASCII value of the characters.
- Hence we return the maxlen as our Output.
Implementation:
#include <bits/stdc++.h>
using namespace std;
// Function to find the maximum length
int maxLen(string s1, string s2, int K) {
int n = s1.size();
int cost = 0, len = 0, maxlen = 0;
for (int i = 0; i < n; i++) {
cost += abs(s1[i] - s2[i]); // add cost
len++;
while (cost > K) { // shrink window
cost -= abs(s1[i - len + 1] - s2[i - len + 1]);
len--;
}
maxlen = max(maxlen, len);
}
return maxlen;
}
int main() {
string s1 = "abcd", s2 = "bcde";
int K = 3;
int result = maxLen(s1, s2, K);
cout << result << "\n";
return 0;
}
import java.util.*;
public class GFG {
// Function to find the maximum length
public static int maxLen(String s1, String s2, int K) {
int n = s1.length();
int cost = 0, len = 0, maxlen = 0;
for (int i = 0; i < n; i++) {
cost += Math.abs(s1.charAt(i) - s2.charAt(i));
len++;
while (cost > K) {
cost -= Math.abs(s1.charAt(i - len + 1) - s2.charAt(i - len + 1));
len--;
}
maxlen = Math.max(maxlen, len);
}
return maxlen;
}
public static void main(String[] args) {
String s1 = "abcd";
String s2 = "bcde";
int K = 3;
int result = maxLen(s1, s2, K);
System.out.println(result);
}
}
# Function to find the maximum length
def maxLen(s1, s2, K):
n = len(s1)
cost = 0
length = 0
maxlen = 0
for i in range(n):
cost += abs(ord(s1[i]) - ord(s2[i]))
length += 1
while cost > K:
cost -= abs(ord(s1[i - length + 1]) - ord(s2[i - length + 1]))
length -= 1
maxlen = max(maxlen, length)
return maxlen
def main():
s1 = "abcd"
s2 = "bcde"
K = 3
result = maxLen(s1, s2, K)
print(result)
if __name__ == "__main__":
main()
using System;
class GFG {
// Function to find the maximum length
static int maxLen(string s1, string s2, int K)
{
int n = s1.Length;
int cost = 0, len = 0, maxlen = 0;
for (int i = 0; i < n; i++) {
cost += Math.Abs(s1[i] - s2[i]);
len++;
while (cost > K) {
cost -= Math.Abs(s1[i - len + 1] - s2[i - len + 1]);
len--;
}
maxlen = Math.Max(maxlen, len);
}
return maxlen;
}
static void Main(string[] args)
{
string s1 = "abcd", s2 = "bcde";
int K = 3;
int result = maxLen(s1, s2, K);
Console.WriteLine(result);
}
}
// Function to find the maximum length
function maxLen(s1, s2, K) {
const n = s1.length;
let cost = 0;
let len = 0;
let maxlen = 0;
for (let i = 0; i < n; i++) {
cost += Math.abs(s1.charCodeAt(i) - s2.charCodeAt(i));
len++;
while (cost > K) {
cost -= Math.abs(s1.charCodeAt(i - len + 1) - s2.charCodeAt(i - len + 1));
len--;
}
maxlen = Math.max(maxlen, len);
}
return maxlen;
}
// Example usage:
const s1 = "abcd";
const s2 = "bcde";
const K = 3;
const result = maxLen(s1, s2, K);
console.log(result);
Output
3