string find 以及 stringstream的用法--由一道上机题说起

今天做了一个上机题,题目很简单,正好重温下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*类型,也可以是单个字符,所以常见的查找的对象基本被包含了。

其中第三个接口被用来查找无“”结果的字符数组/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为""结尾的字符串

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)

原文地址:https://www.cnblogs.com/crafet/p/3661567.html