问题描述:
就是一个字符串分割问题,尽可能分到最小并且一种字符只能出现在一个子字符串
例如:abac —>> aba 和 c
输出:3 1 (每个子串的长度)
注意:要求尽可能短的分割
例如:abacde 不可分割为aba cde 要分割为aba c d e
思路:
- 要求一种字符只能在一起那么两个相同字母以及中间夹住的是必然在一起的。例如:abacab这个串中,aba是在一起的,aca是在一起的。
- 那么一种字母最左边的和最右边的以及夹在中的时必然在一个子串的。例如:abacab这个串中,abaca是必然在一起的。
- 那么每一种字母都这样想的话,我们可以看abaca这个子串中是有另外两种字母b和c的那么其他所有的b和c都要和这个子串在一起的。
解决:
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
int max(int a, int b);
void Resolve(string S, vector<int>& ret);
int main() {
string S;
vector<int> ret;
cin >> S;
Resolve(S,ret);
for (int i = 0; i <(int) ret.size(); i++)
cout << ret[i];
}
void Resolve(string S,vector<int>&ret) {
int Alpha[26];
memset(Alpha, 0, sizeof(Alpha));
//记录每个字符的最右边的下标
for (int i = 0; i <(int) S.length(); i++) {
Alpha[S[i] - 'a'] = i;
}
//设l和r两个指针
int l = 0;
int r = Alpha[S[l]-'a' ];
while (l < (int) S.length()) {
int l0 = l;
while (l < r) {
++l;
r = max(r, Alpha[S[l]-'a']);
}
//将每个子串的长度写入容器
ret.push_back(l - l0 + 1);
l++;
}
}
int max(int a, int b) {
if (a > b)return a;
else return b;
}
解释:
- 我感觉这种方法很巧妙,我的想法就是开始将l和r指针分别在一种字母的最左边一个和最右边一个。
int l = 0;
int r = Alpha[S[l]-'a' ];
- 然后对中间的进行尝试的扩展边界。如果能扩展边界就扩展,不能扩展就保留原来的边界
r = max(r, Alpha[S[l]-'a']);
- 直到 l == r 时扩展结束
- 注意一轮扩展结束之后需要将l指针指向第二个子串首字母的位置
- 直到 l == 到了字符串最后一位结束