LeetCode 1208. 尽可能使字符串相等【不定长滑窗,字符串】1497

本文属于「征服LeetCode」系列文章之一,这一系列正式开始于2021/08/12。由于LeetCode上部分题目有锁,本系列将至少持续到刷完所有无锁题之日为止;由于LeetCode还在不断地创建新题,本系列的终止日期可能是永远。在这一系列刷题文章中,我不仅会讲解多种解题思路及其优化,还会用多种编程语言实现题解,涉及到通用解法时更将归纳总结出相应的算法模板。

为了方便在PC上运行调试、分享代码文件,我还建立了相关的仓库:https://github.com/memcpy0/LeetCode-Conquest。在这一仓库中,你不仅可以看到LeetCode原题链接、题解代码、题解文章链接、同类题目归纳、通用解法总结等,还可以看到原题出现频率和相关企业等重要信息。如果有其他优选题解,还可以一同分享给他人。

由于本系列文章的内容随时可能发生更新变动,欢迎关注和收藏征服LeetCode系列文章目录一文以作备忘。

给你两个长度相同的字符串,st

s 中的第 i 个字符变到 t 中的第 i 个字符需要 |s[i] - t[i]| 的开销(开销可能为 0),也就是两个字符的 ASCII 码值的差的绝对值。

用于变更字符串的最大预算是 maxCost。在转化字符串时,总开销应当小于等于该预算,这也意味着字符串的转化可能是不完全的。

如果你可以将 s 的子字符串转化为它在 t 中对应的子字符串,则返回可以转化的最大长度。

如果 s 中没有子字符串可以转化成 t 中对应的子字符串,则返回 0

示例 1:

java 复制代码
输入:s = "abcd", t = "bcdf", maxCost = 3
输出:3
解释:s 中的 "abc" 可以变为 "bcd"。开销为 3,所以最大长度为 3。

示例 2:

java 复制代码
输入:s = "abcd", t = "cdef", maxCost = 3
输出:1
解释:s 中的任一字符要想变成 t 中对应的字符,其开销都是 2。因此,最大长度为 1。

示例 3:

java 复制代码
输入:s = "abcd", t = "acde", maxCost = 0
输出:1
解释:a -> a, cost = 0,字符串未发生变化,所以最大长度为 1。

提示:

  • 1 <= s.length <= 10^5
  • t.length == s.length
  • 0 <= maxCost <= 10^6
  • st 都只含小写英文字母。

假定字符串 s s s 和 t t t 的长度均为 n n n ,对任意 0 ≤ i < n 0\le i \lt n 0≤i<n ,将 s [ i ] s[i] s[i] 变为 t [ i ] t[i] t[i] 的开销是 ∣ s [ i ] − t [ i ] ∣ | s[i] - t[i] | ∣s[i]−t[i]∣ ,由此可建立一个长度为 n n n 的数组 d i f f diff diff ,其中 d i f f [ i ] = ∣ s [ i ] − t [ i ] ∣ diff[i] = | s[i] - t[i] | diff[i]=∣s[i]−t[i]∣ 。

创建数组 d i f f diff diff 后,问题转换为计算数组 d i f f diff diff 中元素和不超过 m a x C o s t maxCost maxCost 的最长子数组长度 。用前缀和+二分查找 ,或者不定长滑窗很容易解决此题。此处用滑窗更优。

解法 不定长滑窗

由于 d i f f diff diff 的的每个元素都是非负的,因此可以用滑动窗口的方法得到符合要求的最长子数组的长度。

滑动窗口的思想是,维护两个指针 l e f t left left 和 r i g h t right right 表示数组 d i f f diff diff 的子数组的开始下标和结束下标,满足子数组的元素和不超过 m a x C o s t maxCost maxCost ,子数组的长度是 r i g h t − l e f t + 1 right−left+1 right−left+1 。初始时, l e f t left left 和 r i g h t right right 的值都是 0 0 0 。

还要维护子数组的元素和 c o s t cost cost ,初值为 0 0 0 。在移动两个指针的过程中,更新 c o s t cost cost 的值,判断子数组的元素和是否大于 m a x C o s t maxCost maxCost ,并决定应该如何移动指针。

为了得到符合要求的最长子数组的长度,应遵循以下两点原则:

  • 当 l e f t left left 的值固定时, r i g h t right right 的值应尽可能大;
  • 当 r i g h t right right 的值固定时, l e f t left left 的值应尽可能小。

基于上述原则,滑动窗口的做法如下:

  1. 将 d i f f [ r i g h t ] diff[right] diff[right] 的值加到 c o s t cost cost ;
  2. 如果 c o s t ≤ m a x C o s t cost≤maxCost cost≤maxCost ,则子数组的元素和不超过 m a x C o s t maxCost maxCost ,使用当前子数组的长度 r i g h t − l e f t + 1 right−left+1 right−left+1 更新最大子数组的长度;
  3. 如果 c o s t > m a x C o s t cost>maxCost cost>maxCost ,则子数组的元素和大于 m a x C o s t maxCost maxCost ,需要向右移动指针 l e f t left left 并同时更新 c o s t cost cost 的值,直到 c o s t ≤ m a x C o s t cost≤maxCost cost≤maxCost ,此时子数组的元素和不超过 m a x C o s t maxCost maxCost ,使用子数组的长度 r i g h t − l e f t + 1 right−left+1 right−left+1 更新最大子数组的长度;
  4. 将指针 r i g h t right right 右移一位,重复上述步骤,直到 r i g h t right right 超出数组下标范围。

遍历结束之后,即可得到符合要求的最长子数组的长度,即字符串可以转化的最大长度。

java 复制代码
class Solution {
    public int equalSubstring(String s, String t, int maxCost) {
        int n = s.length();
        int ans = 0;
        int cost = 0;
        for (int l = 0, r = 0; r < n; ++r) {
            cost += Math.abs(s.charAt(r) - t.charAt(r));
            while (cost > maxCost) {
                cost -= Math.abs(s.charAt(l) - t.charAt(l));
                ++l;
            }
            ans = Math.max(ans, r - l + 1);
        }
        return ans;
    }
}

复杂度分析:

  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)
相关推荐
阿Y加油吧7 小时前
LeetCode 二叉树双王炸!二叉树展开为链表 + 前序 + 中序还原二叉树|小白递归一把过
算法·leetcode·链表
AI科技星7 小时前
全球AI信息场(信息网)基础理论与数学建模研究(乖乖数学)
开发语言·人工智能·线性代数·算法·机器学习·数学建模
仟濹7 小时前
【算法打卡day37(2026-04-04 周六)】DFS专项训练4-枚举专项训练 1-全部是蓝桥杯真题
算法·蓝桥杯·深度优先
汀、人工智能7 小时前
12 - 内置函数:Python的瑞士军刀
数据结构·算法·数据库架构·图论·python的瑞士军刀
Tisfy7 小时前
LeetCode 3418.机器人可以获得的最大金币数:动态规划
leetcode·机器人·动态规划
羊小猪~~8 小时前
LLM--微调(Adapters,Prompt,Prefix)
算法·ai·大模型·llm·prompt·adapters·prefix
未来之窗软件服务8 小时前
SenseVoicecpp ggml-hexagon.cpp大模型[AI人工智能(七十九)]—东方仙盟
人工智能·算法·仙盟创梦ide·东方仙盟
xiaoye-duck8 小时前
《算法题讲解指南:动态规划算法--子数组系列》--25.单词拆分,26.环绕字符串中唯一的子字符串
c++·算法·动态规划
Fcy6488 小时前
算法基础详解(二)枚举算法——普通枚举与二进制枚举
算法·枚举算法