第一行两个整数 n , m (1<=m<=n<=50000),第二行为长度为n且只包含’a’和’b’的字符串s。
输出在操作次数不超过 m 的情况下,能够得到的 最大连续 全’a’子串或全’b’子串的长度。
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')));
}
}
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; } }
#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; }
# 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))
#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; }
链接: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')))
```
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; } }
## 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))
#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; }
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))
#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; }
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); } }
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)
官方题解的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 }