题目
https://tianchi.aliyun.com/oj/84846268534006540/92553970267132883
给一个只由‘0’-'9'构成的数字串s,|s|<=1e6
任取一个子串,使得子串中出现最多的数字的次数减去子串中出现最少的数字的次数最大,
输出这个最大的差值,
保证串中最少含有至少两种数字
思路来源
https://www.cnblogs.com/liusandao/p/13677695.html
题解
考虑到答案一定是某两个数字,所以枚举所有数字组合的可能,则最大值一定会被枚举到
dp[i][j]表示数字i比数字j当前多了几个,
对枚举的两种数字做最大子段和,与常规最大子段和不同的是,一定要两种不同的数字都出现才可以做差,
所以引入vis,vis[i][0]表示数字i已经出现在序列中,而vis[i][1]表示数字i已经出现在当前dp选定的子段中,
对于vis[j][1]为true的,显然可以更新答案,
vis[j][1]为false但是vis[j][0]为true的,
说明在最后一次重新选取起点时,去掉了最后那个-1,为了两种数字,把-1加上即可
dp[j][v]可以直接减,负的显然不影响更新,而正的保证了j一定出现,
女少口阿!
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
class Solution {
public:
int dp[10][10];
bool vis[10][2];
int key(string &s){
memset(dp,0,sizeof dp);
memset(vis,false,sizeof vis);
int n=s.size(),ans=0;
for(int i=0;i<n;++i){
int v=s[i]-'0';
vis[v][0]=vis[v][1]=true;
for(int j=0;j<10;++j){
if(j==v)continue;
dp[v][j]++;
if(dp[v][j]<=0){
dp[v][j]=1;
vis[j][1]=false;//当前不在dp序列中
}
if(vis[j][1]){
ans=max(ans,dp[v][j]);
}
else if(vis[j][0]){
ans=max(ans,dp[v][j]-1);
}
dp[j][v]--;
ans=max(ans,dp[j][v]);
}
}
return ans;
}
}q;
int main(){
string ans="1110";
printf("%d\n",q.key(ans));
return 0;
}