question:
题目描述:
小明有一个只包含0和1的字符串,现在小明希望将整个字符串尽可能的切割成多个字符串,要求是每个字符串里面0出现的次数和1出现的次数的比例是一致的。解释:假设一个字符串出现0的次数是a次,出现1的次数是b,另一个字符串出现0的次数是c次,出现1的次数是d次,那么这两个字符串01出现次数比例相同表示a:b=c:d,即ad=bc。注意这里a,b,c,d都是可以为0的。现在对于一个字符串的所有前缀字符串,输出最多可以切割成多少个符合要求的字符串。
输入描述:
第一行一个整数n,表示01字符串的长度,1<=n<=500000
第二行一个长度为n的01字符串。
输出描述:
一行n个整数,第i个数表示原字符串中下标由0到i组成的前缀字符串可以切割出多少符合要求的字符串。
样例输入
样例1:
输入:
3
001
输出:
1 2 1
提示:
- 第一个前缀字符串是0,没法切,答案是1
- 第二个前缀字符串是00,可以切得到0,0,答案是2
- 第三个前缀字符串是001,可以切,但是切后没法保证比例要求,因此答案是1
样例2:
输入:
9
010100001
输出:
1 1 1 2 1 2 1 1 3
题目分析与建模:
- 考虑输入:
输入为一个01字符串,记为s
以样例1为例
将s编码为集合或者元组(计算机只能识别离散的编码,因此编码成集合或者元组进行运算)
因为本题考虑分割子串,子串是排列,而非组合,有位置上的区别,因此编码为元组
s=(0,0,1)
- 考虑输出:
输出s字符串各个子字符串即(0),(0,0),(0,0,1)可以分割的符合比例相等的子串的最大个数。
即将s字符串分解为s=((s1),(s2),…,(sk)),使得s1中01比=s2中01比=…=sk中01比。且k要最大。
输入,输出实际上是子字符串集合到可分解最大符合01比条件子串个数的映射,如下所示:
{s.substr([0,i]) | 0<=i<=s.size()-1} -> {(k) | k属于N+}
其中substr表示子串,[0,i]表示从0到i区间的子串,N+表示从1开始的正整数。
-考虑算法与数据结构:
因为让输出的是最大的k值,所以考虑是最优化问题,可以考虑是贪心或者是动态规划。
本题并没有明显的贪心策略,因此考虑是否是动态规划,或者通过暴力枚举手段进行解题。
动态规划两个条件,一个是最优化问题,一个是具有子结构且无后效性。
尝试考虑如下问题:
字符串s=((s1),(s2),…(sk)),设s‘=((s1),(s2),…(sk-1));
则s划分子串时一定有情况s=((s’),(sk));
也就是说,要将s划分成k个01比例相等的子串的子问题就是,将s的某个满足某个01比例的子串划分成k-1个符合该01比例的子串!
s=((s1),(s2),…(sk)) 且这k个子串01比例均为a:b;
其子问题:
s‘=((s1),(s2),…(sk-1)) 且者k-1个子串01比例均为a:b;
用区间表示子串则为:
s.substr([0,i])=s.substr([0,j])+s.substr([j+1,i])
其中s.substr([0,i]) 是k个01比例均为a:b的子串拼成的字符串;
s.substr([0,j])是k-1个01比例均为a:b的子串拼成的字符串;
s.substr([j+1,i])是第k个符合01比例为a:b的子串。
其中0<=i<s.size(),0<=j<I;
回顾之前的集合之间的映射关系,
{s.substr([0,i]) | 0<=i<=s.size()-1} -> {(k) | k属于N+}
根据上面子问题的分析,我们可以得知,划分子串的k的个数与01比例a:b有关,因此我们的映射关系重新表示为:
{s.substr([0,i]) | 0<=i<=s.size()-1} -> {(k,a,b) | a,b,k属于N+}
1.设置状态:
我们把前面这个集合用dp数组表示,dp[i]表示s.substr([0,i])
把后面这个k,a,b用结构体HashNode表示,表示a:b的01比例下,可以划分的子串为k个。
typedef struct HashNode{
int a;
int b;
int k;
HashNode(const int a,const int b,const int count):a(a),b(b),count(k){};
}HashNode;
则映射关系为:dp[i]=[(k1,a1,b1),(k2,a2,b2),…]
上面的映射关系表示为,s的[0,i]区间子串可以划分成k1个以a1:b1为01比例的子串,可以划分成k2个以a2:b2为01比例的子串,…
2.状态转移方程
结合以上的分析,我们可以得到状态转移方程
(设c=s.substr([j+1,i])中0的个数,d=s.substr[j+1,i]中1的个数)
//若遍历dp[j],有比例相等,那么继承dp[j][l]比例,并计算出来的k值加1
if dp[j][l in dp[j].size()].a*d==dp[j][l in dp[j].size()].b*c
dp[i]添加HashNode(dp[j][l].a,dp[j][l].b,dp[j][l].k+1);
//比例不相等情况,不可以进行分割子串
dp[i]添加HashNode(s.substr([0,i])中0个数,s.substr([0,i])中1个数,1)
代码:
#include <iostream>
#include <vector>
#include <string>
#include <queue>
using namespace std;
/*
a:b,0和1的比例
k:能划分的最长子串个数
*/
typedef struct HashNode{
int a;
int b;
int k;
HashNode(const int a,const int b,const int k):a(a),b(b),k(k){};
}HashNode;
//获取字符串s中的0和1的个数,c:0的个数,d:1的个数
void get01Count(string s,int &c,int &d){
c=0;
d=0;
for(int i=0;i<s.size();i++){
if(s[i]=='0') c++;
else d++;
}
}
//重载运算符
ostream& operator<<(ostream &cout,HashNode p){
cout<<"0count:"<<p.a<<",1count:"<<p.b<<",count:"<<p.k<<endl;
return cout;
}
struct cmp{
bool operator()(const HashNode &a,const HashNode &b){
return a.k>b.k;
}
};
vector<vector<HashNode> > getMaxCount(string s){
//初始化dp数组
//dp[i]表示[0,i]区间内的一个结构体,记录了最大划分子串个数和其比例
int size=s.size();
vector<vector<HashNode> > dp(size,vector<HashNode>());
int c=0,d=0;
// vector<priority_queue <HashNode,vector<HashNode>,cmp> > dp(size,priority_queue <HashNode,vector<HashNode>,cmp>());
HashNode temp=HashNode(0,0,1);
temp.a=(s[0]=='0')?1:0;
temp.b=(s[0]=='1')?1:0;
dp[0].push_back(temp);
//[0,i]=[0,j]+substr(j+1,i-j); j属于[0,i-1]
for(int i=1;i<size;i++){
for(int j=0;j<i;j++){
//获取[j+1,i]子串的0,1个数c,d
get01Count(s.substr(j+1,i-j),c,d);
//遍历[0,j]的分割子串的所有情况,如果符合,那么就继承其比例,k++
for(auto l:dp[j]){
if(l.a*d==l.b*c){
cout<<"["<<0<<","<<i<<"]"<<"区间="<<"["<<0<<","<<j<<"]区间+"<<"["<<j+1<<","<<i<<"]区间子串"<<endl;
cout<<"["<<0<<","<<j<<"]区间比例,a:"<<l.a<<",b:"<<l.b<<endl;
cout<<"["<<j+1<<","<<i<<"]区间子串比例,c:"<<c<<",d:"<<d<<endl;
cout<<endl;
HashNode temp=HashNode(l.a,l.b,l.k+1);
dp[i].push_back(temp);
}
}
}
//添加最大可分割就是本身
cout<<s.substr(0,i+1)<<","<<c<<","<<d<<endl;
get01Count(s.substr(0,i+1),c,d);
cout<<"hhhh["<<0<<","<<i<<"]区间比例,c:"<<c<<",d:"<<d<<endl;
cout<<endl;
HashNode temp=HashNode(c,d,1);
dp[i].push_back(temp);
}
return dp;
}
int main(){
string s;
cout<<"请输入01字符串"<<endl;
cin>>s;
vector<vector<HashNode> > dp=getMaxCount(s);
for(auto i:dp){
sort(i.begin(),i.end(),cmp());
cout<<i.front().k<<" ";
}
cout<<endl;
return 0;
}