题目
前缀和 + 二分查找
class Solution {
public int equalSubstring(String s, String t, int maxCost) {
// s变成t只能在对应位置上的字符发生变化, 也就是只能s.charAt(0)变成t.charAt(0)
// 不能是s.charAt(0)变成t.charAt(1)
// 计算出对应位置上的差值
int [] diff = new int[s.length()];
for (int i = 0; i < s.length(); i ++) {
diff[i] = Math.abs(t.charAt(i) - s.charAt(i));
}
// 问题转化成求diff数组中连续子数组的元素和小于maxCost的最大长度
// diff[i] + diff[i + 1] + .... + diff[j] <= maxCost 时, j - i的最大值
// 利用前缀和数组accDiff[i] = diff[0] + diff[1] + ... + diff[i]
int [] accDiff = new int[s.length()];
for (int i = 0; i < s.length(); i ++) {
if (i == 0) {
accDiff[i] = diff[0];
} else {
accDiff[i] = accDiff[i - 1] + diff[i];
}
}
int maxLength = 0;
for(int i = 0; i < accDiff.length; i ++) {
// accDiff[j] - accDiff[i] + diff[i] <= maxCost
// i为左边界, 寻找accDiff[i] + maxCost - diff[i]的右边界j的值
// accDiff为有序数组, 单调增, 利用二分查找
int target = accDiff[i] + maxCost - diff[i];
int j = binarySearch(accDiff, target, i, accDiff.length);
maxLength = Math.max(maxLength, j - i);
}
return maxLength;
}
private int binarySearch(int [] accDiff, int target, int start, int end) {
if (start == end) {
return start;
}
int mid = start + (end - start) / 2;
if (accDiff[mid] == target) {
// 为了解决数组中重复元素
return binarySearch(accDiff, target, mid + 1, end);
} else if (accDiff[mid] < target) {
return binarySearch(accDiff, target, mid + 1, end);
} else {
return binarySearch(accDiff, target, start, mid);
}
}
}
基本思路
-
首先读懂题目, 字符串s中i位置的字符只能变成t字符串中i位置的字符, 而i不能变j.
-
将题目转化成求差分数组连续和小于等于某个值的最大长度
-
利用前缀和计算连续数组和
-
因为是有序数组, 因此可以用二分查找法, 寻找满足条件的最大长度.