题解

难度:中等

知识点:字符串的最长子串问题

分析

方法1:利用下标位置的普通方法,分a、b两种情况处理(较简单)

利用字符下标计算间隔长度,遍历字符串s,以b换a举例:返回所有b的索引值保存在数组中,存为数组indexes=[idx1,idx2,…],(a换b一样)。计算m个b的最大间隔区间,如果b的个数小于等于m,即字符串中不足m个b,全部将他们替换成a即可;否则取“indexes[i]- indexes[i-m-1]-1”的长度的最大值max即为最大连续的相同字符的子串长度,但要注意首位元素的处理。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int len = sc.nextInt();
        int oper = sc.nextInt();
        String str = sc.next();
        System.out.println(Math.max(arraySolve(len, oper, str, 'a'), arraySolve(len, oper, str, 'b')));

    }

    public static int arraySolve(int n, int m, String s, char c) {
        int res = 0;
        List<Integer> indexes = new ArrayList<>();  // 用来存储a/b的所有下标位置
        for (int i = 0; i < n; i++) {
            if (s.charAt(i) == c) {  //用c来替换其他字符,将c所在下标位置加入
                indexes.add(i);
            }
        }

        // 如果要替换的字符个数小于可替换个数,那么直接全部替换即可
        if (indexes.size() <= m) {
            return n;
        }

        // 注意端点位置的处理 
        indexes.add(s.length());
        res = indexes.get(m);
        for (int i = m + 1; i < indexes.size(); i++) {

            res = Math.max(res, indexes.get(i) - indexes.get(i - m - 1) - 1);
        }
        return res;
    } 

方法2:滑动窗口思想解决(要想到连续子串问题都可以用滑动窗口思想来解决)

① 对字符串设置left和right两个指针,初始化left=right=0;而闭区间[left,right]就是窗口。
② 不断增加窗口的right指针,直到窗口中满足题目要求,本题是闭区间中已经更改某个字符(a或b)m次了(用an或bn来表示次数情况),此时相当于找到了解题的可行解。
③ 由于本题是寻找最长子串,所以left指针和right指针要一起往右增加,并且当窗口中改变了相应m次值时更新结果,在一系列可行解中找最优解。

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class Main {

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int len = sc.nextInt();
        int oper = sc.nextInt();
        String str = sc.next();
        System.out.println(windowSolve(str, oper, len));

    }
    private static int windowSolve(String str, int oper, int len) {
        int res=Integer.MIN_VALUE;  
        int left=0, right=0;  // 滑动窗口设置两个指针lr
        int an=0, bn=0;   //用来计数窗口中a/b的个数

        while(right<len){
            if(str.charAt(right)=='a') {
                an++;
            }else {
                bn++;
            }
            // right一直往右走,寻找可行解
            if(an<=oper||bn<=oper){  
                right++;

            }else{  // 从可行解中找最优解:left开始往右走
                // 此时窗口中已经出现了oper个可以改变的字符,更新结果
                res = Math.max(res, right-left);

                // left指针往左走,窗口中退出一个字符相应的计数减1,
                // 而right指针新指的字符计数已经在刚进入while语句时的if判断已加1
                if(str.charAt(left)=='a'){  
                    left++;
                    an--;
                }else{
                    left++;
                    bn--;
                }
                right++;
            }
        }

        res = Math.max(res, right-left);
        return res;
    }
}