10. 字符串
(1)求一个字符串中连续出现次数最多的子串
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "abcbcbcabc";
size_t i, j, k;//用于控制循环
size_t count, maxcount=1;//count用于计数,最小为;maxcount用于记录重复的最大次数,最小为
string subStr;
size_t len = str.size();
for(i=0; i<len; ++i)
{
for(j=i+1; j<len; ++j)//每一次第二层循环结束后都要对maxcount进行更新
{
count = 1;//每次内循环时都要归为
if(str.substr(i, j-i) == str.substr(j, j-i))//判断第一次连续重复的字符串的出现
{
++count;//只要有连续重复的字符串出现,则count至少为
for(k=j+(i-i); k<len && str.substr(i, j-i)==str.substr(k, j-i); ++k)
//寻找后续重复的字符串并计数,这一步只能在已经有重复子串的前提下进行,
//因此应该在第三层循环中进行
++count;
}
if(count > maxcount)
{
maxcount = count;
subStr = str.substr(i, j-i);
}
}
}
cout << "The sub-string \"" << subStr << "\"'s times is " << maxcount << endl;
}
(2)找出字符串中重复出现的最长子串,并输出该子串及其首字符的位置
#include "stdafx.h"
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str = "eabcdbcebcfabc";//结果为abc's index is 1
/*当string str = "ddd"时,结果为dd's index is 0,可见,两个相同的子串可以彼此重叠, 但这时一定是若干个相同字符组成的*/
size_t i, j;//用于控制循环
size_t p1, p2;//pos用于存储重复字符串的位置;p1和p2用于存储正向和逆向搜索子串的位置
string subStr;
size_t len = str.size();
for(i=len-1; i>1; --i)//i为子串的长度,这里并没有强调一定要两个子串不重叠,故子串的最大长度可以为n-1
{
for(j=0; j<len && j+i<=len; ++j)//j+i<=len保证了以j为起始点i为子串长度的子串不会超出原字符串
{
subStr = str.substr(j, i);
p1 = str.find(subStr);
p2 = str.rfind(subStr);
if(p1 != p2)//表明有重复的子串出现,且第一次满足此条件的一定是最长的子串
{
cout << subStr << "\'s index is " << p1 << endl;
return 0;//当运行当此if子句时,则说明已经完成任务,故返回
}
}
}
}
(3)编写strstr()函数,返回值是字符串中子串的位置及其以后的所有字符
#include "stdafx.h"
#include <assert.h>
#include <iostream>
using namespace std;
const char *strstr(const char *str, const char *strSearch)
{
assert(str!=NULL && strSearch!=NULL); //【注】assert函数需要头文件assert.h
int i, j;//内外层循环索引
for(i=0; str[i]!='\0'; ++i)
{
for(j=0; strSearch[j]!='\0' && str[i+j]==strSearch[j]; ++j);
if('\0' == strSearch[j])
return str + i;
}
return NULL;
}
int main()
{
char *str="abcdbcebcfabc", *strSearch="fa";
cout << strstr(str, strSearch) << endl;//输出:fabc
}
(4)字符串倒置问题
① 倒置字符串但保持单词自身的顺序
【思想】采用<csting>头文件中的strtok()函数先将字符串中的单词(字符串的单词被看作是通过’ ’、’,’、’|’、’.’、’;’、’-’等符号被隔开的子字符串)提取出来,然后分别将其存入到list<string>中,最后通过<algorithm>中的copy算法将list的各字符串按逆序打印出来,于是便可以达到目的。
#include <stdafx.h>
#include <cstring>
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
char str[]=", WXL, ,is, ,,,really-a,,,Niu|man. | ";
const char *delims = " ,-|";//delimiter:分隔符,定界符
vector<string> vstr;
// Establish string and get the first token:
char *token = strtok(str, delims);
while( token != NULL )
{
vstr.push_back(token);
// Get next token:
token = strtok( NULL, delims); //NULL is the starting index of the next token substring
}
for(vector<string>::reverse_iterator iter=vstr.rbegin(); iter!=vstr.rend(); ++iter)
//【注】这里要将iter声明为reverse_iterator,因为rbegin函数返回的是reverse_iterator。
cout << *iter << " ";
cout << endl;
//输出也可以通过一条语句来完成:copy(vstr.rbegin(), vstr.rend(), ostream_iterator<string>(cout, " "));
}
② 倒置字符串中的单词的字符顺序但保持单词间的顺序
【思想】采用<csting>头文件中的strtok()函数先将字符串中的单词(字符串的单词被看作是通过’ ’、’,’、’|’、’.’、’;’、’-’等符号被隔开的子字符串)提取出来,然后分别将其存入到vector<string>中,然后对vector中每个元素进行排序,最后通过<algorithm>中的copy算法将vector的各字符串按逆序打印出来,于是便可以达到目的。
#include <stdafx.h>
#include <cstring>
#include <string>
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main()
{
char str[]="pots & pans";
const char *delims = " \t,.;";
vector<string> vstr;
// Establish string and get the first token:
char *token = strtok(str, delims);
while( token != NULL )
{
vstr.push_back(token);
// Get next token:
token = strtok( NULL, delims); //NULL is the starting index of the next token substring
}
// Sort for every sub-string
for(size_t i=0; i<vstr.size(); ++i)
{
for(string::size_type j=0,k=vstr[i].size()-1; j<k; ++j,--k)
swap(vstr[i][j],vstr[i][k]);
}
copy(vstr.begin(), vstr.end(), ostream_iterator<string>(cout, " "));
return 0; //it can be omited
}
(5)转换字符串格式为:原来字符串里的字符+该字符串连续出现的个数,例如字符串:1233422222,转化为1121314125
#include <stdafx.h>
#include <string>
#include <iostream>
using namespace std;
int main()
{
char str[]="1233422222";
size_t i, j, k=0;//i,j为循环控制索引,而k为新数组的索引项
size_t len = strlen(str);
char *newStr = new char [2*len+1];//2*len+1为最坏情况(即无连续相同字符存在)下所占用的空间
size_t n;
for(i=0; i<len; i+=n)
{
for(j=i+1; j<len && str[j]==str[i]; ++j);
newStr[k++] = str[i];
n = j-i;
newStr[k++] = n + '0';//【注】这里必须为n + '0',不能缺少'\0'
}
newStr[k] = '\0';
cout << newStr << endl;
}
(6)计算4000000000以内的最大的那个f(n)=n的值,函数f的功能是统计所有从0到n之间所有含有数字1的数字和
#include <stdafx.h>
#include <string>
#include <iostream>
using namespace std;
int fun(const int n)
{
char str[11];
int i, j;
int num = 0;//存储n中的个数
int len;//len为转换后的字符串的长度,也即原整数的位数
for(i=1; i<=n; ++i)
{
ultoa(i, str, 10); //ultoa函数将unsigned int转化为char *型字符串
len = strlen(str);
for(j=0; j<len; ++j)
{
if('1' == str[j])
++num;
}
}
return num;
}
int main()
{
unsigned int i;//int的范围为-2^31~2^31-1,即-2147483648~2147483647,因此,应该声明为unsigned int
for(i=4000000000; i>=1; --i)
if(i==fun(i))
{
cout << i << endl;
return 0;
}
cout << i << endl;