小美喜欢字母E,讨厌字母F。在小美生日时,小团送了小美一个仅包含字母E和F的字符串,小美想从中选出一个包含字母E数量与字母F数量之差最大的子串。
*子串:从字符串前面连续删去若干个字符,从后面连续删去若干个字符剩下的字符串(也可以一个都不删),例如abcab是fabcab的子串,而不是abcad的子串。我们将空串看作所有字符串的子串。
小美喜欢字母E,讨厌字母F。在小美生日时,小团送了小美一个仅包含字母E和F的字符串,小美想从中选出一个包含字母E数量与字母F数量之差最大的子串。
*子串:从字符串前面连续删去若干个字符,从后面连续删去若干个字符剩下的字符串(也可以一个都不删),例如abcab是fabcab的子串,而不是abcad的子串。我们将空串看作所有字符串的子串。
第一行一个正整数n表示字符串的长度。
第二行长度为n,且仅包含大写字母’E’,’F’的字符串(不含引号)
输出一个整数,表示最大的差值
5 EFEEF
2
选择子串EE,此时有2个E,0个F,有最大差值2-0=2
另外,选择子串EFEE也可以达到最大差值。
对于30%的数据,n<=300
对于60%的数据,n<=3000
对于100%的数据,n<=300000
//贪心,像PAT的最大子列和那题,我的算法启蒙,浙大数据结构的第一讲
#include<iostream>
#include<string>
using namespace std;
int main() {
int n;
cin >> n;
string s;
cin >> s;
int cnt[2] = {0};
int ans = 0;
for (int i = 0; i < n; ++i) {
cnt[s[i] - 'E']++;
if (cnt[0] < cnt[1]) {
cnt[0] = 0;
cnt[1] = 0;
}
ans = max(ans, cnt[0] - cnt[1]);
}
cout << ans << endl;
return 0;
}
package main
import "fmt"
func EF() {
var N int
var str string
fmt.Scan(&N,&str)
cur,max:=0,0
for i:=0;i<N;i++{
if str[i]=='E' {
cur++
if i==N-1&&cur>max{
max=cur
}
}else {
if cur>max{
max=cur
}
cur--
if cur<0{
cur=0
}
}
}
fmt.Println(max)
}
func main(){
EF()
} import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine().trim());
char[] str = br.readLine().trim().toCharArray();
int maxSum = 0, sum = 0;
for(int i = 0; i < n; i++){
if(str[i] == 'E') sum ++;
if(str[i] == 'F') sum --;
maxSum = Math.max(maxSum, sum);
sum = Math.max(sum, 0);
}
System.out.println(maxSum);
}
} import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String gift = sc.next();
// 将字符串转换为数字数组
int[] giftNum = new int[gift.length()];
for (int i = 0; i < gift.length(); i++) {
// E转换为数字1,F转换为数字-1
giftNum[i] = gift.charAt(i) == 'E' ? 1 : -1;
}
method(giftNum, n);
}
// 转换为数字数组之后,这题就相当于求最大子序和了
public static void method(int[] gift, int n) {
// 初始化dp数组
int[] dp = new int[n];
dp[0] = Math.max(gift[0], 0);
int max = dp[0];
// 遍历,根据递推求最大子串和
for (int i = 1; i < dp.length; i++) {
// 每次到达一个新的数字,考虑是加上当前数组总和大还是重头开始总和大
dp[i] = Math.max(dp[i - 1] + gift[i], gift[i]);
// 不断更新最大值
max = Math.max(dp[i], max);
}
System.out.println(max);
}
} import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int len = sc.nextInt();
String str = sc.next();
int[] dp = new int[len];
if (str.charAt(0)=='E') dp[0] = 1;
else dp[0] = 0;
for (int i = 1; i < len; i++) {
if (str.charAt(i) == 'E') {
dp[i] = dp[i-1] + 1;
} else {
dp[i] = Math.max(dp[i-1] - 1, 0);
}
}
int max = Integer.MIN_VALUE;
for (int i = 0; i < dp.length; i++) {
max = Math.max(max, dp[i]);
}
System.out.println(max);
}
} import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
char[] chs = sc.next().toCharArray();
//eNum表示E的数量减去F的数量,如果小于0,重新开始计数,也就是滑动窗口的左端点移至当前下标
int res = 1, eNum = 0;
for (int i = 0; i < n; i++) {
if (chs[i] == 'E') eNum++;
else if (--eNum < 0) eNum = 0;
res = Math.max(res, eNum);
}
System.out.println(res);
}
} 如果是绝对值,多加一个变量,同样的思想: import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
char[] chs = sc.next().toCharArray();
//eNum表示E的数量减去F的数量,如果小于0,重新开始计数,也就是滑动窗口的左端点移至当前下标
//fNum表示F的数量减去E的数量,如果小于0,重新开始计数
int res = 1, eNum = 0, fNUm = 0;
for (int i = 0; i < n; i++) {
if (chs[i] == 'E') {
eNum++;
if (--fNUm < 0) fNUm = 0;
} else {
fNUm++;
if (--eNum < 0) eNum = 0;
}
res = Math.max(res, Math.max(eNum, fNUm));
}
System.out.println(res);
}
} import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
String s = sc.next();
int[] dp = new int[n];
int flag = 0;
if (s.charAt(0) == 'E') {
dp[0] = 1;
} else {
dp[0] = -1;
}
int max = Integer.MIN_VALUE;
for (int i = 1; i < n; i++) {
if (s.charAt(i) == 'E') {
flag = 1;
} else {
flag = -1;
}
dp[i] = Math.max(flag,dp[i - 1] + flag);
if (dp[i] > max) {
max = dp[i];
}
}
System.out.println(max);
}
} using namespace std;
#include<iostream>
#include<string>
#include<vector>
int main(){
int n ;
cin >> n;
string str;
cin >> str;
vector<int> dp(n,0);//dp[i] :包括第i位置之前的“E和F”的差值
if(str[0] == 'E'){//初始化,判断第一个字母是什么
dp[0] = 1;
}
else{
dp[0] = -1;
}
int ans = 0;
for(int i = 1; i < n; i++){
if(str[i] == 'E'){//如果当前位置的字母为E,肯定选取当前位置,在前一个位置的基础上+1;
dp[i] = dp[i-1]+1;
}
else{//如果当前位置的字母是F,判断要不要当前位置,如果要,因为是F所以-1;如果不要重新计数,重置为0;
dp[i] = max(dp[i-1]-1,0);
}
ans = max(ans,dp[i]);//选取一个最大值
}
cout << ans <<'\n';
} #include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
string str;
cin >> str;
vector<int> prefixCt(n + 1, 0);
for (int i = 1; i <= n; ++i) {
prefixCt[i] = (str[i] == 'E' ? 1 : -1) + prefixCt[i - 1];
}
int minCt = 0;
int result = 0;
for (int i = 1; i <= n; ++i) {
result = max(prefixCt[i] - minCt, result);
minCt = min(prefixCt[i], minCt);
}
cout << result;
} 看到“最大“的字样想到动态规划
先将EF字符串转换为1,-1的数组nums
然后明确dp,dp[i]代表以nums[i]结尾的子串的最大和
明确dp方程,dp[i]由前一项和nums[i]决定,如果前一项小于0,则去掉前面的项
// 动态规划
let n = ~~readline()
let str = readline().split('')
let dp = []
// 将EF替换为1,-1
let nums = str.map(item => item == 'E' ? 1 : -1)
// 初始化dp数组
dp[0] = nums[0]
// 初始化最大差值
let max = nums[0]
for(let i = 1 ;i<n;i++){
dp[i] = Math.max(dp[i-1], 0) + nums[i]
max = Math.max(dp[i] ,max)
}
// 依据题意,差值最小时为全F的情况,输出0
print(max >= 0 ? max : 0)
n = int(input()) s = input() res = 0 cur = 0 curMin = 0 for i in range(n): if s[i] == 'E': v = 1 else: v = -1 cur += v curMin = min(curMin, cur) res = max(res, cur - curMin) print(res)