【百度面试题】求包含固定字符集的最短子串
2014-10-09 11:01
155 查看
问题描述:
一串首尾相连的珠子(m个),有N种颜色(N<=10),设计一个算法,取出其中一段,要求包含所有N中颜色,并使长度最短。并分析时间复杂度与空间复杂度。问题可等同于求一个长字符串c中包含固定字符集target的最短子串
如"abddcbda"中包含"abc"的最短子串是"cbda"
算法:
指针head,rear分别指向目前已知的最短子串,初始值为c的头和尾指针begain,end是当前检查的子串,一旦该串包含了全部target,就比较它和已知最短子串的长度,若它更短,设为新的最短子串
数组targetlist记录target中每个元素在begain-end段中出现的次数
begain end初始值均为c的头,对begain end进行的操作如下:
①若end在target中,targetlist中相应元素(end出现的次数)加一,转②若end不在target中转④
②从begain开始检查,若begain出现的次数大于1或者begain不在target中,begain前移,继续检查,直到begain只出现一次。这一步保证begain-end段是在不丢失target的情况下最短的转③
③检车begain-end段,一旦该段包含了全部target,就比较它和已知最短子串(head-rear段)的长度,若它更短,设为新的最短子串。begain++,转④
④end++转①
这样只需一次遍历,就可以找出最短子串,时间复杂度为O(n),n为c长度
空间复杂度为O(n+m) ,m为字符集target中元素的个数
代码实现:
#pragma once #include<iostream> using namespace std; bool Intarget(char* end, char* target, int* clist, int* (&targetlist), int count) { for (int i = 0; i < (int)strlen(target); i++) { if (*(target + i) == *end) { targetlist[i]++;//出现此事加1 clist[count] = i;//end指向的元素是target中第i个元素 return true; } } return false; } //缩减begain-end段,保证它里面目标个数不变的情况下,该段最小 void Reduce(char*(&c), char*(&target),char*(&begain), char*(&end), int*(&clist), int* (&targetlist)) { for (int i = begain - c; i <= end - c; i++) { if (targetlist[clist[i]] > 1)//begain指向的元素出现次数大于1,,begain前移 { begain++; targetlist[clist[i]]--; } else if (clist[i] == -1)//begain指向的元素不在target中,begain前移 begain++; else return; } } //检查begain-end是否包含所有target,若是,且它长度小于head-rear段,将它设为新的head-rear void Checkall(char*(&c), char*(&target), int*targetlist, int* clist, char*(&begain), char*(&end), char*(&head), char*(&rear)) { bool all = true; //检查begain-end这一段,target中的元素是否全都出现 for (int i = 0; i < (int)strlen(target); i++) if (targetlist[i]>0) continue; else { all = false; break; } //head-rear取小值 if (all&& end - begain < rear - head) { head = begain; rear = end; targetlist[clist[begain - c]]--; begain++; } } void Find(char* c, char* target, char* (&head), char* (&rear)) { int *targetlist = new int[strlen(target)]; for (int i = 0; i < (int)strlen(target); i++)//target中元素已出现的次数 targetlist[i] = 0; int *clist = new int[strlen(c)]; for (int i = 0; i < (int)strlen(c); i++)//c中第i个元素在target中的位置 clist[i] = -1; char *begain, *end;//当前正在检查的段 head = c;//指向头 rear = head + strlen(c)-1;//指向尾 begain = end = c; while (*end) { if (Intarget(end, target, clist, targetlist, end - c))//如果*end在target中 { //缩减begain-end段 Reduce(c, target, begain, end, clist, targetlist); //检查begain-end段是否包含所有target,是,则比较长度,小了就生成新的head,rear Checkall(c, target, targetlist,clist, begain, end, head, rear); } end++; } } void main() { char* c = "abddcbdabcd"; char* target = "abc"; int *targetlist = new int[strlen(target)]; char *head = new char; char* rear = new char;//保存最小段 Find(c, target, head, rear); cout << "最短子串长度:" << rear - head +1<< endl; cout << "最短子串:"; for (int i = 0; i <= rear - head; i++) cout << *(head + i)<<' '; cout << endl; cout << "最短子串的head位置:" << head - c << endl; cout << "最短子串的rear位置:" << rear - c << endl; system("pause"); }
运行结果:
![](http://img.my.csdn.net/uploads/201410/09/1412825137_2496.png)
相关文章推荐
- 【百度面试题】求包括固定字符集的最短子串
- 每天学习一算法系列(30)(给一个很长的字符串str 还有一个字符集比如{a,b,c} 找出str 里包含{a,b,c}的最短子串。要求O(n).)
- 包含字符集的最短子串
- 给一个很长的字符串str 还有一个字符集比如{a,b,c} 找出str 里包含{a,b,c}的最短子串。要求O(n)
- 给一个很长的字符串str 还有一个字符集比如"abc" 找出str 里包含"abc"的最短子串。要求O(n)
- 一道题:给一个字符串,和一个字符集,求该字符串包含所有字符集的最短子串
- m个珠子共n种颜色,找出包含n种颜色的最短连续片段(百度面试题)
- 详解人民搜索面试题-求包含所有query的最短距离
- 给定一个字符串,找到包含该字符串所有字符的最短子串
- 百度面试题 求字符串中不含重复字符的最长子串长度
- 找出此产品描述中包含N个关键字的长度最短的子串
- 一个字符串中包含另一个字符串所有字符的最短子串长度?——《编程之美》最短摘要的生成的简化
- 一个字符串中包含另一个字符串所有字符的最短子串长度?——《编程之美》最短摘要的生成的简化
- 微软面试100题:字符串匹配算法,查找包含字符集的子串
- 求有N种颜色的珠子串中包含所有颜色的最短子串
- 求珠子上最短的包含所有颜色的子串
- 【谷歌面试题】找出字符串中只包含两种字符的最长子串
- 百度面试题 最长公共子串-动态规划法
- 每天一道LeetCode-----在字符串s中找到最短的包含字符串t中所有字符的子串,子串中字符顺序无要求且可以有其他字符
- 一道面试题 - 找最长固定unique个数的子串