题目
https://leetcode-cn.com/problems/get-equal-substrings-within-budget/
思路
字符串s与t每一个对应字符的开销为 ∣ s [ i ] − s [ t ] ∣ | s[i] - s[t] | ∣s[i]−s[t]∣因此可以构建一个diff数组其中 d i f f [ i ] = ∣ s [ i ] − s [ t ] ∣ diff[i] = | s[i]-s[t] | diff[i]=∣s[i]−s[t]∣,这样问题就转化成了在diff数组中求区间和不超过maxCost的最长区间长度。
滑动窗口
使用双指针维护一个逻辑上的窗口,不断移动右指针,使用一个变量sum维护当前窗口内的和,当sum > maxCost时更新sum并移动左指针和sum,最后不断跟新答案res即可。
class Solution {
public int equalSubstring(String s, String t, int maxCost) {
int n = s.length();
int[] diff = new int[n];
for (int i = 0; i < n; i++) {
diff[i] = Math.abs(s.charAt(i) - t.charAt(i));
}
int left = 0, right = 0;
int sum = 0, res = 0;
while (right < n) {
sum += diff[right++];
while (sum > maxCost) {
sum -= diff[left];
left++;
}
res = Math.max(res, right - left);
}
return res;
}
}
前缀和 + 二分查找
快速求得一个连续区间的和也可以使用前缀和算法,更具diff数组得到一个前缀和数组sum
int[] sum = new int[n + 1];
for (int i = 1; i < n + 1; i++) {
sum[i] = sum[i - 1] + Math.abs(s.charAt(i - 1) - t.charAt(i - 1));
}
我们想要找到区间
[
i
,
j
]
满
足
s
u
m
[
j
+
1
]
−
s
u
m
[
i
]
<
=
m
a
x
C
o
s
t
[i, j] 满足sum[j + 1] - sum[i] <= maxCost
[i,j]满足sum[j+1]−sum[i]<=maxCost, 我们已经知道了区间的和要小于maxCost 所以
1
<
=
i
<
=
n
时
,
[
0
,
i
−
1
]
区
间
内
的
和
就
是
s
u
m
[
i
]
我
们
需
要
找
到
一
个
开
始
下
标
s
t
a
r
t
,
使
得
[
s
t
a
r
t
,
i
−
1
]
区
间
的
和
小
于
m
a
x
C
o
s
t
,
也
就
是
s
u
m
[
i
]
−
s
u
m
[
s
t
a
r
t
]
<
=
m
a
x
C
o
s
t
所
以
s
u
m
[
s
t
a
r
t
]
>
=
s
u
m
[
i
]
−
m
a
x
C
o
s
t
1<= i <= n时,[0, i- 1]区间内的和就是sum[i]我们需要找到一个开始下标start,使得[start, i - 1]区间的和小于maxCost,也就是sum[i] - sum[start] <= maxCost 所以sum[start] >= sum[i] - maxCost
1<=i<=n时,[0,i−1]区间内的和就是sum[i]我们需要找到一个开始下标start,使得[start,i−1]区间的和小于maxCost,也就是sum[i]−sum[start]<=maxCost所以sum[start]>=sum[i]−maxCost,由于diff数组都为正数,所以前缀和数组单调递增,可以通过二分查找来对每一个
i
i
i查找最小的
s
t
a
r
t
下
标
start下标
start下标,每次查找到的最长区间长度为
i
−
s
t
a
r
t
i - start
i−start, 每查找一次更新答案res即可
class Solution {
public int equalSubstring(String s, String t, int maxCost) {
int n = s.length();
int[] sum = new int[n + 1];
for (int i = 1; i < n + 1; i++) {
sum[i] = sum[i - 1] + Math.abs(s.charAt(i - 1) - t.charAt(i - 1));
}
// sum数组是单调递增的
int res = 0;
for (int i = 1; i <= n; i++) { // sum[i] - sum[start] <= maxCost => sum[start] >= sum[i] - maxCost
int start = binarySearch(sum, i, sum[i] - maxCost);
res = Math.max(res, i - start);
}
return res;
}
int binarySearch(int[] sum, int end, int target) {
int lo = 0, hi = end;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (sum[mid] < target) {
lo = mid + 1;
} else {
hi = mid;
}
}
return lo;
}
}