今天做了一个上机题,题目很简单,正好重温下std::string类的一些接口以及stringstream的简单用法。
题目:给定一个正整数,看作字符串,判断这个数是否包含两次或者两次以上的子串。
如“12121”就包含两次“12”,
再如”12345“就不包含重复的子串。
一、std::string的find接口介绍
首先解决一个问题,判定一个串t是否在串s中出现过的次数。这个可以使用std::string提供的find接口。
这个接口的原型为:
size_t find(string&str, size_t pos = 0); size_t find(char*s, size_t pos = 0); size_t find(char*s, size_t pos, size_type n); size_t find(char c, size_t pos =0);
重载的4个接口里,返回类型均为size_t类型。
如果找到对应的pattern,那么返回pattern在s中的第一个下标位置。
如果查找失败,那么返回string::npos,这个值定义为常量-1
static const size_t npos = -1;
参数中的pattern既可以是string类型,也可以是char*类型,也可以是单个字符,所以常见的查找的对象基本被包含了。
其中第三个接口被用来查找无“\0”结果的字符数组/buffer。查找的长度为n。
string s = "abcdefg12"; char t[3]={'d','e','f'}; size_t idx = s.find(t, 0, 3); //cout << idx << endl;//3
如果不指定n,那么就是第二个find声明,即期望patter为"\0"结尾的字符串
pos指的是从母串s中开始查找的位置下标。
二、利用find接口查找重复子串
const int TIMES = 2; bool check_dup_str(string& s, string& t) { size_t idx = 0; size_t beg = 0; idx = s.find(t, beg); while(string::npos != idx) { ++count; beg = idx + t.length(); idx = s.find(t, beg); } if (count >= TIMES) { return true; } else { return false; } }
函数check_dup_str用来检测t在s中出现的次数是否大于等于2,如果是返回true,否则返回false。
这里使用了find的第一个重载的接口,t为对应的pattern, pos为母串中开始查找的位置。每次查找到一个pattern后,计数,同时跳过pattern的长度,在余下的母串中继续查找。
三、完成题目
这里直接蛮力解决,找出所有的子串,然后调用check_dup_str进行检查,一旦找到第一个满足的情况就退出。
int check_dup_str(string& s) { bool found_flag = false; for (int i = 0; !found_flag && i < s.length()-1; i++) { for (int j = i+1; j < s.length(); j++) { string tmp_str = s.substr(i, j-i+1); if (is_t_in_s_2(s, tmp_str)) { found_flag = true; break; } } } // for if (found_flag) { return 1; } else { return 0; } }
蛮力枚举子串就不多说,这里提下,退出两层循环的常用方法:“内部break+外部布尔变量”。
这里找到第一个满足的子串就退出函数。或者在内部for中直接return出来。
如果需要在两层for之后继续其他逻辑,不想直接return,那么就内部先break出来,由于break只能退出一层,为了同时退出外层循环,可以break之前设置一个flag,这里是found_flag,使得退出内部for之后,found_flag为true,同时在外层循环中设置对这个flag的依赖。
当外层for需要继续迭代的时候,由于依赖了内部设置的flag,因此会直接退出外层for循环,这样就实现了二层循环的退出。
这应该是大一时候学习的方法吧,汗,早就忘记了,今天也是急中生智想出来:(。
四、main函数
int _tmain(int argc, _TCHAR* argv[]) { int input; cin >> input; string str; stringstream ss; ss << input; ss >> str; cout << check_dup_str(str) << endl; return 0; }
这里提到一下stringstream的用法,其实在C的<stdio。h>中包含了一些int/char/char*之间的转换,而stringstream则是采用对象封装的形式实现了这些基本常用类型之间的转换。老式转换中<stdio.h>,需要小心处理申请的缓冲区大小。如itoa, atoi等。
而stringstream内部封装了buffer,可以根据具体的转换类型自行管理缓冲区,因此带来了方便。
本题中将int转型为string类型。当然也可以string到int,类比同样可以char*到int等。(char*到string,string(char*), 再到int)