Boundary update without `+1` / `-1`
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.
Move from brute-force thinking to an efficient approach using binary search strategy.
You are given two strings s and t of the same length and an integer maxCost.
You want to change s to t. Changing the ith character of s to ith character of t costs |s[i] - t[i]| (i.e., the absolute difference between the ASCII values of the characters).
Return the maximum length of a substring of s that can be changed to be the same as the corresponding substring of t with a cost less than or equal to maxCost. If there is no substring from s that can be changed to its corresponding substring from t, return 0.
Example 1:
Input: s = "abcd", t = "bcdf", maxCost = 3 Output: 3 Explanation: "abc" of s can change to "bcd". That costs 3, so the maximum length is 3.
Example 2:
Input: s = "abcd", t = "cdef", maxCost = 3 Output: 1 Explanation: Each character in s costs 2 to change to character in t, so the maximum length is 1.
Example 3:
Input: s = "abcd", t = "acde", maxCost = 0 Output: 1 Explanation: You cannot make any change, so the maximum length is 1.
Constraints:
1 <= s.length <= 105t.length == s.length0 <= maxCost <= 106s and t consist of only lowercase English letters.Problem summary: You are given two strings s and t of the same length and an integer maxCost. You want to change s to t. Changing the ith character of s to ith character of t costs |s[i] - t[i]| (i.e., the absolute difference between the ASCII values of the characters). Return the maximum length of a substring of s that can be changed to be the same as the corresponding substring of t with a cost less than or equal to maxCost. If there is no substring from s that can be changed to its corresponding substring from t, return 0.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Binary Search · Sliding Window
"abcd" "bcdf" 3
"abcd" "cdef" 3
"abcd" "acde" 0
longest-nice-subarray)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1208: Get Equal Substrings Within Budget
class Solution {
private int maxCost;
private int[] f;
private int n;
public int equalSubstring(String s, String t, int maxCost) {
n = s.length();
f = new int[n + 1];
this.maxCost = maxCost;
for (int i = 0; i < n; ++i) {
int x = Math.abs(s.charAt(i) - t.charAt(i));
f[i + 1] = f[i] + x;
}
int l = 0, r = n;
while (l < r) {
int mid = (l + r + 1) >>> 1;
if (check(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
private boolean check(int x) {
for (int i = 0; i + x - 1 < n; ++i) {
int j = i + x - 1;
if (f[j + 1] - f[i] <= maxCost) {
return true;
}
}
return false;
}
}
// Accepted solution for LeetCode #1208: Get Equal Substrings Within Budget
func equalSubstring(s string, t string, maxCost int) int {
n := len(s)
f := make([]int, n+1)
for i, a := range s {
f[i+1] = f[i] + abs(int(a)-int(t[i]))
}
check := func(x int) bool {
for i := 0; i+x-1 < n; i++ {
if f[i+x]-f[i] <= maxCost {
return true
}
}
return false
}
l, r := 0, n
for l < r {
mid := (l + r + 1) >> 1
if check(mid) {
l = mid
} else {
r = mid - 1
}
}
return l
}
func abs(x int) int {
if x < 0 {
return -x
}
return x
}
# Accepted solution for LeetCode #1208: Get Equal Substrings Within Budget
class Solution:
def equalSubstring(self, s: str, t: str, maxCost: int) -> int:
def check(x):
for i in range(n):
j = i + mid - 1
if j < n and f[j + 1] - f[i] <= maxCost:
return True
return False
n = len(s)
f = list(accumulate((abs(ord(a) - ord(b)) for a, b in zip(s, t)), initial=0))
l, r = 0, n
while l < r:
mid = (l + r + 1) >> 1
if check(mid):
l = mid
else:
r = mid - 1
return l
// Accepted solution for LeetCode #1208: Get Equal Substrings Within Budget
struct Solution;
impl Solution {
fn equal_substring(s: String, t: String, max_cost: i32) -> i32 {
let s: Vec<char> = s.chars().collect();
let t: Vec<char> = t.chars().collect();
let n = s.len();
let mut cost: Vec<i32> = vec![0; n];
for i in 0..n {
cost[i] = (s[i] as i32 - t[i] as i32).abs();
}
let mut start = 0;
let mut end = 0;
let mut res = 0;
let mut sum = 0;
while end < n {
if sum <= max_cost {
sum += cost[end];
end += 1;
} else {
sum -= cost[start];
start += 1;
}
if sum <= max_cost {
res = res.max(end - start);
}
}
res as i32
}
}
#[test]
fn test() {
let s = "abcd".to_string();
let t = "cdef".to_string();
let max_cost = 3;
let res = 1;
assert_eq!(Solution::equal_substring(s, t, max_cost), res);
let s = "abcd".to_string();
let t = "acde".to_string();
let max_cost = 0;
let res = 1;
assert_eq!(Solution::equal_substring(s, t, max_cost), res);
}
// Accepted solution for LeetCode #1208: Get Equal Substrings Within Budget
function equalSubstring(s: string, t: string, maxCost: number): number {
const n = s.length;
const f = Array(n + 1).fill(0);
for (let i = 0; i < n; i++) {
f[i + 1] = f[i] + Math.abs(s.charCodeAt(i) - t.charCodeAt(i));
}
const check = (x: number): boolean => {
for (let i = 0; i + x - 1 < n; i++) {
if (f[i + x] - f[i] <= maxCost) {
return true;
}
}
return false;
};
let l = 0,
r = n;
while (l < r) {
const mid = (l + r + 1) >> 1;
if (check(mid)) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
Use this to step through a reusable interview workflow for this problem.
Check every element from left to right until we find the target or exhaust the array. Each comparison is O(1), and we may visit all n elements, giving O(n). No extra space needed.
Each comparison eliminates half the remaining search space. After k comparisons, the space is n/2ᵏ. We stop when the space is 1, so k = log₂ n. No extra memory needed — just two pointers (lo, hi).
Review these before coding to avoid predictable interview regressions.
Wrong move: Setting `lo = mid` or `hi = mid` can stall and create an infinite loop.
Usually fails on: Two-element ranges never converge.
Fix: Use `lo = mid + 1` or `hi = mid - 1` where appropriate.
Wrong move: Using `if` instead of `while` leaves the window invalid for multiple iterations.
Usually fails on: Over-limit windows stay invalid and produce wrong lengths/counts.
Fix: Shrink in a `while` loop until the invariant is valid again.