力扣 1208. 尽可能使字符串相等 二分 滑动窗口

54 篇文章 1 订阅
18 篇文章 0 订阅
本文介绍了三种不同的解决方案来解决LeetCode上的一个问题,即在不超过最大成本的情况下找到相等子串的最大长度。第一种方法是二分查找,时间复杂度为O(nlogn)。第二种和第三种方法都是滑动窗口策略,但第三种方法通过优化更新左边界的方式减少了运算次数,保持了窗口长度的单调性,时间复杂度为O(n)。这些方法展示了在解决字符串处理问题时如何利用滑动窗口和二分查找优化算法效率。
摘要由CSDN通过智能技术生成

https://leetcode-cn.com/problems/get-equal-substrings-within-budget/
在这里插入图片描述
思路一:考虑枚举转换的字符串的长度,那么在 O ( s . l e n g t h ) O(s.length) O(s.length)内即可计算出在 c o s t cost cost限制下是否有解,那么可以从 1 1 1开始枚举直到不满足题意为止,但是这样做会超时。不难发现转换的字符串长度和消耗的代价是有单调性的(这里仅考虑最优解),所以可以上二分,那么复杂度大概为 O ( n l g n ) O(nlgn) O(nlgn),可以通过。

class Solution {
public:
    int equalSubstring(string s, string t, int maxCost) {
        int n=s.size();
        int l=0,r=n,mid;
        while(l<=r)
        {
            mid=(l+r)>>1;
            bool flag=true;
            int sum=0;
            for(int i=0;i<mid;i++)
                sum+=abs(s[i]-t[i]);
            flag=sum>maxCost;
            for(int i=mid;i<n&&flag;i++)
            {
                sum+=abs(s[i]-t[i])-abs(s[i-mid]-t[i-mid]);
                flag=sum>maxCost;
            }
            if(flag)
                r=mid-1;
            else
                l=mid+1;
        }
        return r;
    }
};

思路二:直接维护一个满足题意的滑动窗口,分别移动右左边界记录最大值即可。复杂度 O ( n ) O(n) O(n)

class Solution {
public:
    int equalSubstring(string s, string t, int maxCost) {
        int cost=0,l=0,r=0,n=s.size(),ans=0;
        while(r<n)
        {
            cost+=abs(s[r]-t[r]);
            ++r;
            while(cost>maxCost)
            {
                cost-=abs(s[l]-t[l]);
                ++l;
            }
            ans=max(ans,r-l);
        }
        return ans;
    }
};

思路三:依然是滑动窗口,但是我们可以进一步优化。考虑思路二中的代码,每一次循环都会把右边界 + 1 +1 +1,然后依据限制条件调整左边界,最后我们得到了一个满足题意的区间 [ l , r ) [l,r) [l,r),由于最后要返回最大值,那么我们是否可以在滑动区间的同时维持区间长度单调不减呢?答案是可以的,只需要把修改左边界的那部分代码放到 i f if if语句中,这样在每次循环中,只有两种情况: 1. r = r + 1 , l 1.r=r+1,l 1.r=r+1,l不变; 2. r = r + 1 , l = l + 1 2.r=r+1,l=l+1 2.r=r+1,l=l+1。可以看到区间长度是单调不减的。正确性?完整的证明我是给不了了,不过可以这样理解,假设最优解对应的区间为 [ l 2 , r 2 ) [l_2,r_2) [l2,r2),我们现在位于区间 [ l 1 , r 1 ) [l_1,r_1) [l1,r1),显然: r 2 − l 2 > = r 1 − l 1 r_2-l_2>=r_1-l_1 r2l2>=r1l1,所以当 l 1 = l 2 l_1=l_2 l1=l2时一定有 r 1 < = r 2 r_1<=r_2 r1<=r2,这种情况下我们一定能得到新的最优解 [ l 2 , r 2 ) [l_2,r_2) [l2,r2),由于窗口长度是单调不减的,所以当 r 2 = n r_2=n r2=n时我们可以得到答案 n − l 2 n-l_2 nl2。虽然总体复杂度依然是 O ( n ) O(n) O(n),不过可以减少一些运算次数。

class Solution {
public:
    int equalSubstring(string s, string t, int maxCost) {
        int cost=0,l=0,r=0,n=s.size();
        while(r<n)
        {
            cost+=abs(s[r]-t[r]);
            ++r;
            if(cost>maxCost)
            {
                cost-=abs(s[l]-t[l]);
                ++l;
            }
        }
        return n-l;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值