首页 > 试题广场 >

编程题2

[编程题]编程题2
  • 热度指数:12868 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 64M,其他语言128M
  • 算法知识视频讲解
有一个仅包含’a’和’b’两种字符的字符串s,长度为n,每次操作可以把一个字符做一次转换(把一个’a’设置为’b’,或者把一个’b’置成’a’);但是操作的次数有上限m,问在有限的操作数范围内,能够得到最大连续的相同字符的子串的长度是多少。

输入描述:
第一行两个整数 n , m (1<=m<=n<=50000),第二行为长度为n且只包含’a’和’b’的字符串s。


输出描述:
输出在操作次数不超过 m 的情况下,能够得到的 最大连续 全’a’子串或全’b’子串的长度。
示例1

输入

8 1
aabaabaa

输出

5

说明

把第一个 'b' 或者第二个 'b' 置成 'a',可得到长度为 5 的全 'a' 子串。
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;


/**
 * 利用前缀和数组
 * 例如:
 * n=10,m=1,s=baabaabaab
 *   b a a b a a b a a b
 *   0 1 2 3 4 5 6 7 8 9
 *   
 *   将 b-->a
 *   b 的前缀和数组为
 *          sums={ 0, 3, 6, 9, 10}//10 为字符串长度
 *   计算长度分别为: 
 *          3  6-0-1=5   9-3-1=5  10-6-1=3
 *     ==>>max = max{ max, sums[i]-sum[i-m-1]-1}
 */

public class Main{
    public static int change(int n, int m, String s, char k) {
        int max = 0;
        List<Integer> sums = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == k) {
                sums.add(i);
            }
        }
        if (sums.size() <= m) {
            return n;
        }
        sums.add(s.length());
        max = sums.get(m);
        for (int i = m + 1; i < sums.size(); i++) {
            max = Integer.max(max, sums.get(i) - sums.get(i - m - 1) - 1);
        }
        return max;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        String s = scanner.next();
        System.out.println(Integer.max(change(n, m, s, 'a'), change(n, m, s, 'b')));
    }
}
发表于 2019-02-01 02:44:10 回复(9)
您的代码已保存
正在查询结果...

等到花儿都谢了
发表于 2020-02-18 22:28:43 回复(0)
连续字符串问题均可以转换成滑动窗口
窗口内记录a b的个数,当窗口内a b个数均大于m  窗口右移,否则窗口扩大
import java.util.*;

public class Main{
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int m = sc.nextInt();
        String s = sc.next();
        System.out.println(helper(s,m,n));
    }
    
    private static int helper(String s,int m,int n){
        int max = 0;
        int l = 0,r = 0;//滑动窗口初始值
        int a = 0,b = 0;//窗口内a和b的个数
        char[] ss = s.toCharArray();
        while(r < n){
            if(ss[r] == 'a') 
                ++a;
            else 
                ++b;
            //窗口内a b的个数有一个小于等于m
            if(m >= a || m >= b)
                ++r;
            else{
                //窗口内a b个数均大于m,说明此时最大了不能在扩展了,需要移动窗口
                max = Math.max(max,r - l);
                //判断左边是a 还是b 将对应个数减去
                if(ss[l++] == 'a')
                    --a;
                else
                    --b;
                ++r;
            }
        }
        max = Math.max(max,r - l);
        return max;
    }
}


发表于 2021-03-26 13:29:55 回复(0)
#include <bits/stdc++.h>
using namespace std;

int main(){
    string s;
    int n, m;
    scanf("%d%d", &n, &m);
    cin>>s;
    int l=0, r=0, a=0, b=0, Max=0;
    for(;r<=n;r++){
        if(s[r]=='a')
            a++;
        else
            b++;
        if(a>m && b>m){
            Max = max(Max, r-l);
            if(s[l]=='a')
                a--;
            else
                b--;
            l++;
        }
    }
    Max = max(Max, r-l);
    printf("%d\n", Max);
    return 0;
}

发表于 2020-12-05 00:47:56 回复(0)
# O(n)复杂度的解法
def main(s,m):

    a_index = [i for i in range(len(s)) if s[i] == 'a']
    b_index = [i for i in range(len(s)) if s[i] == 'b']
    a_index = [-1] + a_index + [len(s)]
    b_index = [-1] + b_index + [len(s)]
    if len(a_index)-2 <= m or len(b_index)-2 <= m:
        return len(s)
    else:
        max_a = [a_index[i+m]-a_index[i-1]-1 for i in range(1,len(a_index)-m)]
        max_b = [b_index[i+m]-b_index[i-1]-1 for i in range(1,len(b_index)-m)]
        return max(max_a+max_b)

n,m = list(map(int,input().strip().split()))
s = input().strip()

print(main(s,m))
发表于 2019-06-02 11:42:02 回复(1)
#include <bits/stdc++.h>
using namespace std;
int presuma[50005];
int presumb[50005];
int main() {
    int n, m; cin >> n >> m;
    string s; cin >> s;
    for (int i=0; i<n; i++) {
        if (s[i] == 'a') {
            presuma[i+1] = presuma[i] + 1;
            presumb[i+1] = presumb[i];
        }
        else {
            presuma[i+1] = presuma[i];
            presumb[i+1] = presumb[i] + 1;
        }
    }
    int i=1, j=1, ans = 0;
    while(j <=n) {
        if (presuma[j] - presuma[i-1] <= m) {
            ans = max(ans, j-i+1);
            j++;
        } else {
            i++;
        }
    }
    i = 1; j = 1;
    while(j <=n) {
        if (presumb[j] - presumb[i-1] <= m) {
            ans = max(ans, j-i+1);
            j++;
        } else {
            i++;
        }
    }
    cout << ans << endl;
    return 0;
}
编辑于 2019-04-12 22:30:09 回复(1)

链接:https://blog.csdn.net/ansizhong9191/article/details/88365647

以b替换a为例,记录每一个b的位置,那么将连续m个b的置换为a必然存在最长的字串。对索引为i的b而言,将前面m个b置换为a,此时索引为i的b与索引为i-m-1的b之间的字串的长度为loc[i] - loc[i-m-1]-1。初始化时,i从m+1开始,因为前面不足m个b的时候,只要全部置为a即可。

``` python
def change(alpha):  
    loc = list() # loc存的是当前字符是ALPHA的位置  
    for i in range(len(s)):  
        if s[i] == alpha:  
            loc.append(i)
    loc.append(n) # 最后一个alpha以后的另一种字符情况也要计算,所以要加上len(s)              
    length = loc[m] # 当所有字符都为alpha是,最大的连续字符情况是m,所以说长度一定大于m\  
    for i in range(m + 1, len(loc)):          
        length = max(length, loc[i] - loc[i - m] - 1) 
    return length
n, m = list(map(int, input().split()))
s = input() print(max(change('a'), change('b')))

```

发表于 2019-04-12 13:07:09 回复(0)
import java.util.Scanner;
public class Main {
    public static void main(String[] args)
    {
        Scanner scan=new Scanner(System.in);
        while(scan.hasNext()){
            int n=scan.nextInt();
            int m=scan.nextInt();
            String s=scan.next();
            int a=get('a',n,m,s);
            int b=get('b',n,m,s);
            System.out.println(Math.max(a,b));
        }
    }
    public static int get(char ch,int n,int m,String s){
        int []data=new int[n+2];
        data[0]=-1;
        int poi=1;
        for(int i=0;i<n;i++){
            if(s.charAt(i)==ch){
                data[poi]=i;
                poi++;
            }
        }
        data[poi]=n;
        int ans=0;
        for(int i=0;i+m+1<=poi;i++){
            ans=Math.max(ans,data[i+m+1]-data[i]-1);
        }
        if(m>=poi)
            return n;
        else
            return ans;
    }
}

发表于 2019-04-11 15:19:45 回复(0)
## 19:45 -- 20:27
n, m = [int(x) for x in input().split()]
s = input()
max_a = 0
max_b = 0
a_index = []
b_index = []
for i in range(n):
    if s[i] == 'a':
        a_index.append(i)
    else :
        b_index.append(i)
if len(a_index) <= m or len(b_index) <= m :
    print(n)
else :
    for i in range(len(a_index) - m):
        if i == 0:
            temp = a_index[m]
            if temp > max_b :
                max_b = temp
        elif i == len(a_index) - m :
            temp = n - a_index[i]
            if temp > max_b :
                max_b = temp
                print(i)
        else :
            temp = a_index[m+i] - a_index[i-1] - 1
            if temp > max_b :
                max_b = temp
    
    for i in range(len(b_index) - m):
        if i == 0:
            temp = b_index[m]
            if temp > max_a :
                max_a = temp
        elif i == len(b_index) - m :
            temp = n - b_index[i]
            if temp > max_a :
                max_a = temp
        else :
            temp = b_index[m+i] - b_index[i-1] - 1
            if temp > max_a :
                max_a = temp
    print(max(max_a, max_b))

发表于 2019-02-17 20:27:55 回复(1)
a换b时:
1、遍历字符串,返回所有b的索引值,存为数组num=[num1,num2, , , ,]
2、取包含m个b的最大区间,num[i+m]-num[i-1]-1,注意首位处理
3、比较得到最大值
编辑于 2018-10-04 16:46:05 回复(4)
复杂度O(n)解法: 设置两个指针l,r分别指向当前最长可行翻转的子串(也就是该串的'a'或者'b'字符加起来不超过m的子字符串)的头和尾,遍历一次字符串即可求解。
#include<stdio.h>

char c[50010];
int n, m;

int main(){
    scanf("%d%d", &n, &m);
    for(int i=0;i<n;i++) scanf("%c", &c[i]);
    int maxl=0, l=0, r=0, an=0, bn=0;
    while(r<=n){
        if(c[r]=='a') an++;
        else bn++;
        if(an<=m||bn<=m){
            r++;
        }else{
            if((r-l)>maxl) maxl=r-l;
            if(c[l]=='a'){
                l++;
                an--;
            }else{
                l++;
                bn--;
            }
            r++;
        }
    }
    if((r-l)>maxl) maxl=r-l;
    printf("%d", maxl);
    return 0;
}

编辑于 2019-04-13 10:50:44 回复(6)
def length(s, n, m):
    res = m                    # 初始化长度为m,因为即使是把前m个字符全改成a或b也没问题
    num_a = s[:m].count("a")   # 记录a的个数
    num_b = m - num_a          # 记录b的个数
    start = 0                  # 记录起始下标
    for i in range(m, n):      # 开始遍历
        if s[i]=='a':
            num_a += 1         # 更新a的个数
        else:
            num_b += 1         # 更新b的个数
        if min(num_a, num_b) <= m:    # 这种情况说明m个替代操作内可以使字符串变成一种
            res = max(res , i-start+1)# 以s[i]结尾的情况下的最大长度为i-start+1
        elif s[start] == 'a':  # 当a和b的长度都超过m时,起点必须要变才能使m个操作内的替代成立
            num_a -= 1         # 如果起点位置为a,则更新a的个数
            start += 1         # 更新起点位置
        else:
            num_b -= 1         # 如果起点位置为a,则更新a的个数
            start += 1         # 更新起点位置
    return res
n,m = map(int, input().split(' '))
s = input()
print(length(s, n, m))

发表于 2019-08-19 16:17:15 回复(3)
一个比较蹩脚的做法。。。。 (其实前缀和数组完全可以不用,也没必要分开求解)
#include<bits/stdc++.h>
using namespace std;

int ac[50010], bc[50010];
int main(){
    int n, m;
    cin>>n>>m;
    string s;
    cin>>s;
    for(int i=0;i<s.length();i++){
        ac[i+1] = ac[i] + (s[i]=='a');
        bc[i+1] = bc[i] + (s[i]=='b');
    }
    int l=1, r=1, res=1;
    while(r<=s.length()){ // calculate ans after the condition.
        if(ac[r]-ac[l-1] <=m) res = max(r-l+1, res); // to include l, minus ac[l-1]
        if(ac[r] - ac[l-1]<=m) r++;
        else l++;
    }
    l=1, r=1;
    while(r<=s.length()){
        if(bc[r]-bc[l-1] <=m) res = max(r-l+1, res);
        if(bc[r] - bc[l-1]<=m) r++;
        else l++;
    }
    cout<<res;
}


另外一种滑动窗口非常简单!
#include<bits/stdc++.h>
using namespace std;

int main(){
    int n, m;
    cin>>n>>m;
    string s;
    cin>>s;
    int l=0, r=0, res=1, ac=0, bc=0;
    while(r<s.length()){ 
        ac += s[r] == 'a';
        bc += s[r] == 'b';
        if(ac<=m||bc<=m) r++;
        else{
            res = max(res, r-l);
            ac -= s[l] == 'a';
            bc -= s[l] == 'b';
            l++;
            r++;
        }
    }
    cout<<res;
}


发表于 2020-08-25 14:28:19 回复(0)
但是覅偶偶送到姥姥家发射机的法律框架离开家里都是JFK拉进来破哦地方经济·1
发表于 2023-08-24 11:34:03 回复(0)
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        // 注意 hasNext 和 hasNextLine 的区别
        int m = in.nextInt();
        int k = in.nextInt();
        in.nextLine();
        String s = in.nextLine();
        int cnt = 0;
        int l=0, r = 0, ant = 0, bnt = 0;
        int res = 0;
        while(r < m){
            char c = s.charAt(r);
            if(c == 'a'){
                ant++;
            }else{
                bnt++;
            }

            while(Math.min(ant,bnt) > k){
                if(s.charAt(l)=='a'){
                    l++;
                    ant--;
                }else{
                    l++;
                    bnt--;
                }
            }
            res = Math.max(res, r - l+1);
            r++;
        }
        System.out.println(res);   
    }
}

发表于 2023-03-08 22:39:38 回复(0)
n,m=map(int,input().split())
s=list(input())

def getmax(s,m,c):
    left,right,ans,cnt=0,0,0,0
    while right<len(s):
        if s[right]==c:right+=1
        else:
            cnt+=1
            right+=1
            # 这里因为用了一次修正所以 right往后移动一次
            while(cnt>m):
                # 超过修正次数了
                if s[left]!=c:cnt-=1
                left+=1
        ans=max(ans,right-left)
    return ans

max_len=0
max_len=max(getmax(s,m,'b'),getmax(s,m,'a'))
print(max_len)

发表于 2022-08-20 18:01:04 回复(0)
def length(c,m,n):
    l=[]
    if len(c)<=m:
        return n
    else:
        for i in range(0,len(c)-m+1):
            if i==0:
                l.append(c[i+m]) 
            elif i+m==len(c):
                l.append(n-1-c[i-1])
            else:
                l.append(c[i+m]-c[i-1]-1)
    res=0
  #  print(len(l))
    for x in l:
        if x>res:
            res=x
    return res    

n,m=map(int,input().split())
s=input()
cnt=0
cnt=s.count('a')
#print(cnt)
c=[]
d=[]
#if cnt<=len(s)-cnt:
c.append(s.find('a'))
while c[-1]!=-1:
    c.append(s.find('a',c[-1]+1))
c.pop()
 #   print(len(c))
    #print(c)
    
    #print(length(c,m,n))
#else:
d.append(s.find('b'))
while d[-1]!=-1:
    d.append(s.find('b',d[-1]+1))
d.pop()
    #print(len(c))
    #print(c)
print(max(length(c,m,n),length(d,m,n)))
发表于 2022-08-18 18:08:04 回复(0)

官方题解的GO版本

package main

import(
    "fmt"
    "bufio"
    "os"
)

func main() {
    var n, m int
    fmt.Scan(&n)
    fmt.Scan(&m)
    reader := bufio.NewReaderSize(os.Stdin, n)
    line, _, _ := reader.ReadLine()
//     fmt.Println(max(arraySolve(n, m, line, 'a'), arraySolve(n, m, line, 'b')))
    fmt.Println(windowSolve(line, m, n))
}

func arraySolve(n, m int, s []byte, c byte) int {
    res := 0
    indexes := make([]int, 0) //存储所有的a/b字符的下标
    for i := 0; i < n; i++ {
        if s[i] == c {
            indexes = append(indexes, i)
        }
    }

    // 全部替换即可
    if len(indexes) <= m {
        return n
    }

    // 在最后面补一位,防止漏掉最后一个连续子串的情形
    indexes = append(indexes, n)
    // indexes[m]表示前面刚好有m个a/b,将它们全部替换掉得到的子串长度res即为indexes[m]指向的下标
    res = indexes[m]
    for i := m+1; i < len(indexes); i++ {
        // indexes[i] 与 indexes[i-m-1]之间共有m+1个a/b,而indexes[i-m-1]本身就是a/b,因此再减去1,就可以得到最长子串
        res = max(res, indexes[i]-indexes[i-m-1]-1)
    }
    return res
}

func windowSolve(str []byte, m, n int) int {
    var res int
    left, right := 0, 0
    cntA, cntB := 0, 0 
    for right < n {
        if str[right] == 'a' {
            cntA++
        } else {
            cntB++
        }
        if cntA > m && cntB > m {
            res = max(res, right-left)
            if str[left] == 'a' {
                cntA--
            } else {
                cntB--
            }
            left++
        }
        right++
    }
    res = max(res, right-left)
    return res
}

func max(a, b int) int {
    if a > b {
        return a
    }
    return b
}
发表于 2022-07-12 10:49:34 回复(0)
package main

import(
    "fmt"
)

func main(){
    n,m := 0,0
    var str string
    fmt.Scanln(&n,&m)
    fmt.Scanln(&str)
    arr := []byte(str)
    pair := [2]int{}
    res := 0
    for l,r := 0,0; l <= r;{
//      右指针前移   
        for r < len(arr) && (pair[0] <= m || pair[1] <= m){
            if arr[r] == 'a'{
                pair[0]++
            }else{
                pair[1]++
            }
            r++
        }
//      子解   
        if r-l-1 > res{
            res = r-l-1
        }
//      右指针到头,子解变小,无效子解   
        if r == len(arr){
            break
        }
//      左指针前移   
        if arr[l] == 'a'{
            pair[0]--
        }else{
            pair[1]--
        }
        l++
    }
    fmt.Println(res)
}
发表于 2022-04-05 16:38:27 回复(0)
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main{
/**
 * 利用前缀和数组
 * 例如:
 * n=10,m=1,s=baabaabaab
 *   b a a b a a b a a b
 *   0 1 2 3 4 5 6 7 8 9
 *   
 *   将 b-->a
 *   b 的前缀和数组为
 *          sums={ 0, 3, 6, 9, 10}//10 为字符串长度
 *   计算长度分别为: 
 *          3  6-0-1=5   9-3-1=5  10-6-1=3
 *     ==>>max = max{ max, sums[i]-sum[i-m-1]-1}
 */

    public static int change(int n, int m, String s, char k) {
        int max = 0;
        List<Integer> sums = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == k) {
                sums.add(i);
            }
        }
        if (sums.size() <= m) {
            return n;
        }
        sums.add(s.length());
        
        for (int i = 0; i+m+1 < sums.size(); i++) {
          
        int tmp =sums.get(i+m+1)-sums.get(i )-1;
            if(tmp>max)max=tmp;
        }
        return max;
    }

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        int m = scanner.nextInt();
        String s = scanner.next();
        System.out.println(Integer.max(change(n, m, s, 'a'), change(n, m, s, 'b')));
    }
}
发表于 2022-03-20 16:22:02 回复(0)