标签:子串 前缀 int res 最长 备考 机试 平衡 Day19
题目
BUPT 2018 计算机 ProblemD
给定只含01的字符串,找出最长平衡子串的长度(平衡串:包含0和1的个数相同)
输入描述
多组测试数据输入。
输入一串01字符串,字符串长度最大为100000。
输出描述
请输出最长的平衡子串的长度。
示例
输入
101011000
输出
8
题解
刚开始理解错题意了,以为一定是要从头开始的子串,后来看了题解发现是任意位置的子串都可,暴力破解就是O(
n
2
n^2
n2),会超时,于是学习了下面这种解法
前缀和O(n)解法
思路:把这里的0换成-1,然后利用前缀和思想找最长平衡串
模拟过程:
- 前缀和:d[i]代表s前i位之和
- 用到这道题上找最长平衡串就是找
d[i]==0
的最大i或者d[i]-d[j]==0
的最大i,j之差
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
---|---|---|---|---|---|---|---|---|
s | 1 | 0 | 0 | 0 | 1 | 0 | 1 | – |
d | – | 1 | 0 | -1 | -2 | -1 | -2 | -1 |
- m[i]表示d[i]与其起始位置的映射关系
d | 1 | -1 | -2 |
---|---|---|---|
m | 1 | 3 | 4 |
所以你找到最长平衡串了吗?应该是s[3]~s[6]长度为4的子串,也刚好是d[7]-d[3]==0
最大i,j之差的点
代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
string s;
while(cin>>s)
{
int res=0;
int d[s.length()+1];//记录前缀和
d[0]=0;
map<int,int>m;//用map进行d[i]与其最开始位置的映射
for(int i=1;i<=s.length();i++)
{
/*计算前缀和*/
int tmp=s[i-1]=='0'?-1:1;//0转成-1
d[i]=d[i-1]+tmp;//前缀和关键
/*最长平衡串判定*/
if(d[i]==0)//d[i]为0,说明从头到i就是平衡串
res=max(res,i);
else
{
if(m[d[i]]==0)//d[i]不是0且开始位置还没有被记录过,则记录开始位置
m[d[i]]=i;
else//开始位置被记录过,说明和上次位置之间的子串可构成平衡串
res=max(res,i-m[d[i]]);//更新res
}
}
cout<<res<<endl;
}
}
真的是相当的妙啊
小结
前缀和
举个例子很好理解,长为n的a数组,一共有m个询问,每次问[l,r]范围内的数字之和是多少?
这里d数组就是a数组的前缀和,即d[3]=a[1]+a[2]+a[3]
如果要求[3,5]区间内的数字和的话直接用d[5]-d[3-1]
就可以得到了,时间复杂度为O(n)
标签:子串,前缀,int,res,最长,备考,机试,平衡,Day19 来源: https://blog.csdn.net/qq_43417265/article/details/113768614
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。