c与指针 从一个字符串中提取子串_笔试 | 字节跳动 完美字符串 two pointers

字节跳动20200809笔试 完美字符串

某天你得到了一个长度为n(1<=n<=500000)的字符串,并且这个字符串只包含小写字母。现在允许你修改m(1<=m<=n)个位置的字母,修改完毕你要选取这个字符串的一个连续子串,如果这个子串只包含一种字母,那么这个连续子串是一个完美字符串。你希望得到的完美字符串长度尽可能长,请计算出你所能得到的最长长度是多少。

样例输入
  • 8 1
  • aabaabaa
样例输出
  • 5(把任意一个b换成a,得到的最长完美字符串为aaaaa)
样例输入
  • 8 2
  • aabaabaa
样例输出
  • 8 (把两个b都换成a,得到最长完美子串为aaaaaaaa)
思路
  • 这个题要求的是最后能得到的最长的完美子串的长度是多少,这个完美子串是由「同一个字符」构成的。那么可以枚举下最后最长的这个完美子串是由哪个字母组成的。
  • 那么问题就转换成了「如何求只包含某一个字符的最长的完美串」。解决这个问题之后可以遍历26个字母中的每一个,然后就能得到最终的答案了。
  • 以字母'a'为例。这个子问题是一个典型的利用two pointers来解决的问题。设置两指针left和right,分别表示当前考虑的子串的起点和终点坐标。每次我们尝试移动right指针,如果right指针所指向的字符不是'a',那么我们可以用一个替换操作把它换成'a';换完之后如果替换的机会已经用完了,那么就需要得把左边的指针往右边移动,直到替换的次数不超过m个。这个时候,left和right所指向的子串就是一个满足要求的。
  • 拿第一个样例举例来看。最开始left=right=0,固定left让right持续往右走,直到遇到第一个b(下标为2),这个时候我们可以用一次替换的操作把这个b换成a。然后可以继续往前走,直到遇到第二个b,尝试去把第二个b换成a,换完之后发现替换操作我们用了两次,所以就让left指针尝试往右走,将多余的那次操作给抹掉,当left=2的时候,使用的操作数减1,我们就又得到了一个符合条件的完美串。继续往下执行即可。。也就是说,当right到达下一个位置的时候,判断当前修改次数是否满足要求,如果满足要求那么更新答案;否则往前移动left指针,直到修改次数满足要求
  • 时间复杂度,O(n * 26)
代码

c++

#include 

using namespace std;

int main() {
    int n, m; cin >> n >> m;
    string s; cin >> s;
    int ans = 0;
    for (int i = 0; i 26; ++i) { // 尝试看每一个字母
        int left = 0, used = 0; // left表示左指针,used表示当前修改了几次
        for (int right = 0; right // 右指针,
            if (s[right] != 'a' + i) { // s[right]不是我们要的字母,用一次修改机会
                used++;
            }
            while (used > m) { // 检查目前的修改次数是否超出了预算
                if (s[left++] != 'a' + i) { // 持续挪动左指针,直到修改次数不超过m
                    used--;
                }
            }
            ans = max(ans, right - left + 1); // left到right之间的字符串是满足要求的
        }
    }
    cout <endl;
    return 0;
}

python 

n, m = input().split(' ')
n, m = int(n), int(m)
ans = 0
s = input()
for i in range(26):
    left, used = 0, 0
    for right in range(n):
        if ord(s[right]) != ord('a') + i:
            used += 1
        while used > m:
            if ord(s[left]) != ord('a') + i:
                used -= 1
            left += 1
        ans = max(ans, right - left + 1)
print(ans)

代码提交地址

https://codeforces.com/contest/676/problem/C

类似题
  • https://leetcode.com/problems/longest-substring-without-repeating-characters/
  • https://leetcode.com/problems/subarrays-with-k-different-integers/
  • https://leetcode.com/problems/max-consecutive-ones-iii/
  • https://leetcode.com/problems/count-number-of-nice-subarrays/
e705eef0942d5099398949e31b124412.gif 6690b77fb31df862176c60b4d3e2c813.gif 46155afee6e65cf0d44c6050ddd69167.png 6690b77fb31df862176c60b4d3e2c813.gif扫码关注我们 49205996c91407a45ffdf5c3d471f628.gif仙女都在看点点点,赞和在看都在这儿! b5bd42e7d012983ea35173bade947618.png
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值