《程序员面试宝典》部分字符串题目
2014-08-15 16:43
204 查看
// 1.题目:求一个字符串中连续出现次数最多的子串 《程序员面试宝典》P225 /*基本算法描述: 理解(一): 给出一个字符串abcbcbcabc 1.穷举出所有的后缀子串 substrs[0] = abcbcbcabc; substrs[1] = bcbcbcabc; substrs[2] = cbcbcabc; substrs[3] = bcbcabc; substrs[4] = cbcabc; substrs[5] = bcabc; substrs[6] = cabc; substrs[7] = abc; substrs[8] = bc; substrs[9] = c; 1.第一行第一个字符a,与第二行第一个字符b比较,不等,则 2.第一行前两个字符ab,与第三行前两个字符cb比较,不等,则 3.第一行前三个字符abc,与第四行前三个字符bcb比较,不等,则 4.第一行前四个...... 上述过程就相当于在原始字符串中, 第一趟,a与b比较,ab与cb比较,abc与bcb比较,abcb与cbca比较,abcbc与bcabc比较,abcbcb与cabc比较...... 第二趟,b与c比较,bc与bc比较(相等,则继续向后取长度为2的子串比较(子串间隔j-i),碰到不等为止,本例中因碰到ab停止),bcb与cbc比较...... 第三趟,c与b比较,cb与cb比较(相等),cbc与bca比较...... */ #include <iostream> #include <string> #include <vector> #include <utility> #include <stdio.h> using namespace std; pair<int,string> fun(const string &str)//求一个字符串中连续出现次数最多的子串,输出子串以及出现的次数 { int count = 1, maxcount = 1; vector<string> substrs; string substr; int len = str.length(); cout<<"所给字符串的子串如下:"<<endl; for(int i = 0; i < len; i++) { substrs.push_back(str.substr(i));//str.substr(i,length)表示从第i个开始截取length的长度,如果length为空,则截取到结尾。 cout<<substrs[i]<<endl; } cout<<count<<endl; for(int i = 0; i < len; i++)//遍历趟数 { for(int j = i+1; j < len; j++)//每一趟,某一行与其他行的比较 { count = 1;//此处要重新给count赋值,因为循环后count已经累加过了 if(substrs[i].substr(0,j-i) == substrs[j].substr(0,j-i))//注意这里参与比较的个数实际是j-i,而非j-1,因为j随着i增大了 { count++; //方法一:同一子串选择不同的起点 for(int m = 1 ;(j-i)*m < len-j; m++)//len-j 是第j行的长度 { if(substrs[i].substr(0,j-i) == substrs[j].substr(m*(j-i),j-i))//注意这里第二个匹配的起点其实是j-i,因为substrs下标从0开始 count++; else break; } //方法二:选择不同子串进行匹配 // for(int k=j+(j-i); k<len; k+=j-i) // { // if (substrs[i].substr(0,j-i) == substrs[k].substr(0, j-i)) // ++count; // else // break; // } if(count > maxcount) { maxcount = count; substr = substrs[i].substr(0,j-i); } } } } return make_pair(maxcount,substr); } // 2.题目:输入一行字符串,输出其中出现的相同且长度最长的字符串及其首字符位置 《程序员面试宝典》P226 /*算法描述: 首先将字符串分解成后缀子串,根据题目一的思想,最长字符串的相同字符串的首字符必然相同,找到首字符相同的后 接着往下比较,直到遇到不同的或者字符串末尾,记下这段字符串,赋值给maxstr。下次循环的时候得到字符串后与 maxstr长度比较,如果比之大就赋值给maxstr。循环结束,返回maxstr和首字符。 substrs[0] = abcbcbcabc; substrs[1] = bcbcbcabc; substrs[2] = cbcbcabc; substrs[3] = bcbcabc; substrs[4] = cbcabc; substrs[5] = bcabc; substrs[6] = cabc; substrs[7] = abc; substrs[8] = bc; substrs[9] = c; */ pair<int, string> fun1(const string &str) { vector<string> substrs; int pos = 0, len = str.length(); //cout<<"子串如下"<<endl; for(int i = 0; i < len; i++) { substrs.push_back(str.substr(i)); //cout<<substrs[i]<<endl; //输出后缀子串 } string maxstr = "\0";//默认最长为空 //cout<<"maxstr默认长度"<<maxstr.length()<<endl; for(int i = 0; i < len; i++) for(int j = i+1; j < len; j++) { if(substrs[i].substr(0,1) == substrs[j].substr(0,1)) { //初始化 if (maxstr.length() < 1) { pos = i+1; maxstr = substrs[j].substr(0,1); } for(int m = 1; m < len-j; ++m) { if(substrs[i].substr(m,1) == substrs[j].substr(m,1))//依次比较字符 { if(m+1 > maxstr.length())//如果找到更长的串,重新给pos和maxstr赋值 { pos = i+1; maxstr = substrs[i].substr(0,m+1); } } else break; } } } return make_pair(pos,maxstr); } //其他实现方法 http://blog.csdn.net/jimoshuicao/article/details/10163121#cpp pair<int,string> fun2(const string &str) { int index=0; int maxlen=0; string substr; int i=0,j=0; int len=str.length(); int k=i+1; int s,lt; while(i<len) { j=str.find(str[i],k); //从(k~len-1)范围内寻找str[i] if(j==string::npos )//若找不到,说明(k~len-1)范围内没有str[i] { i++; k=i+1; } else { //若找到,则必有(j>=i+1) s=i; lt=1; while(str[++s]==str[++j] && j<len){} lt=s-i; if(lt>maxlen) { maxlen=lt; substr=str.substr(i,lt); index=i+1; } k=j; }//else }//while return make_pair(index,substr); } /* 书中程序思想: 按照长度递减去寻找相同的子串,只要找到第一对相同的子串,则立刻退出程序。 因为是按照长度递减的顺序去寻找子串,所以必定能找到最长的相同子串。 以abcab为例子分析如下: 首先寻找长度为4的子串,只能是abca和bcab,再查看这两个子串是否有其他相同的子串。有的话直接输出结果并退出程序。 然后寻找长度为3的子串,只能abc,bca,cab。这3个子串都没有其他相同的子串。 最后寻找长度为2的子串,首先是ab,用find函数返回在abcab中正序查找的位置0,用rfind函数返回在abcab中逆序查找的位置3。 这两个位置不相等,说明在不同的位置存在相同的子串ab。直接输出ab:1,然后退出程序。 */ pair<int, string> fun3(const string &str) { int pos = 0; int len = str.length(); string maxlen = "\0"; for(int j = len-1; j >= 1; j--)//控制查找的字符串长度,从最长的开始查找 for (int i = 0; i+j <= len; i++)//控制开始查找的位置 { if (str.find(str.substr(i,j),i+1) != string::npos)//对每一个串str.substr(i,j),从i+1开始查找,只要找到就赋值返回 //if (str.find(str.substr(i,j)) != str.rfind(str.substr(i,j))) //如果正序查找返回的结果和逆序查找返回结果不一样,也说明找到了。 { pos = i+1; maxlen = str.substr(i,j); return make_pair(pos,maxlen); } } } //题目3:写一个程序,模拟C++的strstr()函数:给定主串和子串,在主串中查找子串,返回从第一个子串开始的所有主串剩下的部分 //例如给定主串“abcdgdf”和子串“cdg”,返回“cdgdf” /*分析: 首先把子串第一个字符与主串第一个字符比较,如果不相等,i++继续与主串下一个位置比较;如果找到相等的,比较子串剩下的字符, 一旦有一个不相等,i++与主串下一个比较,如果到了子串末尾了还都相同,则说找到匹配,则输出*/ char *strstr1(string &str, string &substring) { int flag = 0; int i = 0, m = 0,j = 0; //string sstr; while(!flag && str[i] != '\0')//设置标志位,如果找到匹配的,立即结束整个循环;如果搜索到主串末尾还没搜到,也结束 { for(j = 0; substring[j] != '\0'; j++)//子串范围内比较 { if(substring[j] != str[i+j])//一旦找到不相等的,立即跳出循环,移动主串指针到下一个 { flag = 0; break; } else if(substring[j+1] == '\0')//如果全部想等,并且已经比较到子串末尾了,证明找了匹配了,flag置1, { //结束整个循环。一定注意是“==”!!!,一点错误,查了好久! flag = 1; break; } } i++;//移动主串的指针,指向下一个 } if(str[i] != '\0')//如果是因为找到匹配的而非是因为到了主串末尾而结束,才输出 { // for(int k = i-1; str[k] != '\0'; k++) // sstr[m++] = str[k]; // sstr[m] = '\0'; return &str[i-1];//直接返回这个指针,输出的时候就是这个指针之后的整个字符串 } else return NULL;//没找到,返回空 } /*题目4:将一句话里的单词倒置,标点符号不到换。如I come from China. 变成China. from come I 《程序员面试宝典》P225 分析1:从后到前,以空格为分界线,利用"+"连接字符串(或者apend()函数)直接进行字符串连接。 分析2:思路和1差不多,利用容器 分析3:先整体反转,然后再把每个单词反转*/ //char *senrev(string &str) string senrev(string &str) { //string str = "I come from China."; vector<string> svec; if(str.empty())//首先确定字符非空 return NULL; int m = 0; int j = str.length()-1;// // int j = 0; string revstring; //思路2,利用容器 // for(int i = 0; i <= str.length(); i++) // { // if(str[i] == ' ' || str[i] == '\0')//遇到空格或者结束符,就把这中间的单词加到容器里面 // { // m = i; // svec.push_back(str.substr(j,m-j));//从j = 0开始 // j = m+1; // } // } // for(vector<string>::reverse_iterator iter = svec.rbegin(); iter != svec.rend(); iter++) // { // revstring += *iter; // if(iter != svec.rend()-1)//只要不是最后一个单词,都需要加个空格 // revstring += " "; // } // 思路1,用append()函数连接 // for(int i = str.length()-1; i >= 0; i--) // { // if(str[i] == ' ')//找到空格 // { // m = i+1; // revstring = revstring.append(str.substr(m,j-i));//插入空格与j之间的字符串 // revstring = revstring.append(" ");//只要不是第一个单词的最后,都需要插入空格 // j = i-1;//j前移到前一个单词的终点 // } // if(i == 0)//如果到了字符串开始,就插入第一个单词,即起点为0,长度为m-1的子串 // revstring = revstring.append(str.substr(0,m-1)); // // } // 思路1,用“+”连接 for(int i = str.length()-1; i >= 0; i--) { if(str[i] == ' ')//搜索空格 { m = i+1; revstring += str.substr(m,j-i);//插入空格与j之间的字符串 revstring += " ";//只要不是第一个单词的最后,都需要插入空格 j = i-1;//j前移到前一个单词的终点 } if(i == 0)//如果到了字符串开始,就插入第一个单词,即起点为0,长度为m-1的子串 revstring += str.substr(0,m-1); } return revstring; } /*题目5:字符串压缩。通过键盘输入一串小写字母(a~z)组成的字符串相同字符串用数字代替 。例如 输入gaaabbbbccddde 压缩后成 g3a4b2c3de 思路:首先指针指向字符串第一个字符,如果下一个字符与这个字符不同,直接将这个字符加到 新字符串上;如果与下一个字符串相同,得到相同字符的个数,把这个数字转换成字符并连同这 个字符一起加到新字符上,指针指向下一个新字符。直到程序结尾。*/ string strzip(string &str) { string zipstr; int len = str.length(); int j = 0, count = 1; char tempstr[8]; for(int i = 1; i <= len; i++) { if(str[j] == str[i])//如果下一个字符和当前字符相同,count加一 count++; else//遇到不同的字符,准备写入新字符串 { if(count == 1)//如果只有一个,直接写入这个字符 zipstr += str[j]; else { // char tempstr[8] = {0}; // sprintf(tempstr,"%d",count); // zipstr = zipstr + tempstr + str[j]; memset(tempstr,0,8);//每次,把tempstr置零,方便写入count zipstr = zipstr + itoa(count, tempstr, 10) + str[j]; //直接把字符串连接起来 } count = 1;//写完之后,count置1 j = i;//j指针移动到下一个未写的字符上 } } return zipstr; } //完全用sprintf,有问题 // char *strzip1(string &str) // { // char zipstr[100]; // int len = str.length(); // int j = 0, count = 1; // // for(int i = 1; i <= len; i++) // { // if(str[j] == str[i]) // count++; // else // { // if(count == 1) // sprintf(zipstr+strlen(zipstr),"%c",str[j]); // else // { // // char tempstr[8] = {0}; // // sprintf(tempstr,"%d",count); // // zipstr = zipstr + tempstr + str[j]; // // sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2); // sprintf(zipstr+strlen(zipstr),"%d%c",count,str[j]); // // char tempstr[8] = {0}; // //zipstr = zipstr + itoa(count, tempstr, 10) + str[j]; // } // count = 1; // j = i; // // } // } // return zipstr; // } int main() { //string str = "aaaabcbcbcbcabccccc"; // string str = "yyabcdabjcabceg"; // string substring; //string str = "abbcdfe"; /*第1题 pair<int,string> rs; rs=fun(str); cout<<"出现次数最多的子串是: "<<rs.second<<endl<<"出现的次数是: "<<rs.first<<endl; */ /*第2题 pair<int,string> rs; rs = fun3(str); cout<<"位置: "<<rs.first<<endl<<"最大字符串"<<rs.second<<endl; */ /*第3题*/ // cout<<"The original string is :"<<str<<endl; // cout<<"Please input the substring that need to be searched:"<<endl; // cin>>substring; // if(strstr1(str,substring) == NULL) // cout<<"Can not find!"<<endl; // else // cout<<strstr1(str,substring)<<endl; /*第4题*/ // string str = "I come from China."; // for(int i = 0; i < str.length(); i++) // cout<<str[i]; // cout<<endl; // cout<<senrev(str)<<endl; /*第5题*/ string str = "gaaabbbbccddde"; cout<<str<<endl; cout<<strzip(str)<<endl; //练习 char s[50] = {0}; char* who = "I"; char* whom = "CSDN"; sprintf(s, "%s love %s%d.", who, whom,123); //产生:"I love CSDN. " cout<<s<<endl; char a1[] = {'A', 'B', 'C', 'D', 'E', 'F', 'G'}; char a2[] = {'H', 'I', 'J', 'K', 'L', 'M', 'N'}; // sprintf(s, "%s%s", a1, a2); //Don't do that! //sprintf(s, "%.7s%.7s", a1, a2);//产生:"ABCDEFGHIJKLMN" sprintf(s, "%.6s%.5s", a1, a2);//产生:"ABCDEFHIJKL" // sprintf(s, "%.*s%.*s", sizeof(a1), a1, sizeof(a2), a2); cout<<s<<endl; return 0; }
相关文章推荐
- 程序员面试宝典(第三版)部分题目解答
- // 程序员面试宝典 面试题目2 217 将字符串转化为整型 不能使用atoi函数。接口仿照atoi ,
- 第十部分 字符串处理和正则表达式---------------
- 把字符串放到规定的范围内,超出的部分自动变为"..."完美解决
- ORACLE数据库部分面试题目
- asp下实现截取字符串特定部分内容函数
- ORACLE数据库部分面试题目
- C#-优化字符串操作(转自清清月儿,且删除部分)
- 详解华为java华为面试题(转自suningin,个人补充了部分题目参考答案)
- 去除一个字符串的开头和结束部分的空格,中间有连续的两个或两个以上的空格,则保留一个空格
- [原创]对字符串中包含数字的部分进行数值运算
- 把字符串放到规定的范围内,超出的部分自动变为"..."完美解决 shilong [原作]
- 截取固定长度字符串显示在页面,多余部分显示为省略号(区分汉字和字符)
- 根据自定义字符串来缓存(部分)页面
- 面试C++题目,字符串拷贝与小写换大写
- 截取固定长度字符串显示在页面,多余部分显示为省略号(区分汉字和字符)
- 控制字符串的超长部分用省略号表示
- 截取固定长度字符串显示在页面,多余部分显示为省略号(区分汉字和字符)
- CutString 字符串截除指定长度后的部分(考虑汉字字符串)
- 世界最佳公司面试题部分题目解答要点