[leetCode]1208. 尽可能使字符串相等

本文讲解了如何使用滑动窗口算法和前缀和技巧解决LeetCode上关于字符串s和t中子串匹配的成本问题,通过计算字符差异和维护最大成本范围找到最长相等子串。关键步骤包括构建diff数组,滑动右指针并调整左边界,以及利用前缀和进行区间和查找。
摘要由CSDN通过智能技术生成

题目

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,i1]sum[i]start使[start,i1]maxCostsum[i]sum[start]<=maxCostsum[start]>=sum[i]maxCost,由于diff数组都为正数,所以前缀和数组单调递增,可以通过二分查找来对每一个 i i i查找最小的 s t a r t 下 标 start下标 start,每次查找到的最长区间长度为 i − s t a r t i - start istart, 每查找一次更新答案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;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值