感谢者望守想梦 http://blog.csdn.net/u012999424 所提供的面试经历
题目:一个char数组只包含a,b,c,d,e五种字符,设计一种算法,找出一个包含五种字符的最小区间,数组是循环的。
思路: 1、建立索引 front, rear指向子区间的首和尾
2、rear自增遍历数组,设立count[5]存储每种字符出现的个数,设立num记录出现字符的种类数量
3、当num=5时,rear停止自增,front开始自增并且count[*(src+front)]-'a']--,直到其中一个字符为0。这样就找到了符合条件的子区间,但不一定是最小的。
4、判断front和rear与已记录的最小区间
5、重复2-4,遍历字符数组两遍
O(n)算法
#include <iostream>
using namespace std;
void minSubString(char *src, char *des){
int length=strlen(src)-1; //字符串长度
int turn=0; //记录循环次数
int min=strlen(src);
int minfront=0;
int minrear=0;
int front, rear;
front=rear=0;
int allChar=strlen(des); //记录需要匹配的字符种类个数
int num=0; //记录一共多少种字符出现
int count[5]={0,0,0,0,0}; //记录每个字符出现次数
char *p=src;
char c; //临时存储字符
while( turn<2 ) {
c = *(p+rear);
if(c=='\0') { //进入下一次循环遍历
rear=0;
turn++;
continue;
}
if(count[c-'a'] == 0) {
num++;
count[c-'a']++;
}
else {
count[c-'a']++;
}
if(num == allChar) { //所要求的字符集已全部检索
while(1) {
c = *(p+front);
if(c=='\0') {
front++;
continue;
}
count[c-'a']--;
if(count[c-'a'] == 0) { //字符集中某个字符出现次数为0
if(rear<front)
rear=rear+strlen(src);
if(rear-front < min){ //此处的front依旧指向那个出现次数为0的字符
min=rear-front;
minfront=front;
minrear=rear-strlen(src);
}
count[c-'a']++; //回退,开始新的子串检索
break;
}
front++;
if(front>strlen(src)){
front=0;
}
}
}
rear++;
}
//输出处理
cout<<("最小区间");
cout<<minfront;
cout<<(" ");
cout<<minrear;
cout<<endl;
if(minrear>minfront) {
for(int i=minfront; i<=minrear; i++)
cout<<*(p+i);
}
else if(minrear<minfront) {
for(int i=minfront; i<strlen(src); i++) {
cout<<*(p+i);
}
for(int j=0; j<=minrear; j++)
cout<<*(p+j);
}
cout<<endl;
}
int main() {
char *src="eabbbbbcdabcdacccaeaabcd";
char *des="abcde";
minSubString(src,des);
return 0;
}