如何找到使用STL算法分隔字符串中两个不同字母的最短星号序列?

时间:2017-10-09 13:37:51

标签: c++ algorithm stl

我有一个这样的字符串:

A*A**B***A**

我对两个不同字母之间的星号序列感兴趣,特别是我需要找到最短这种序列的长度。对于上面的字符串,答案当然是2:A**B

我可以使用传统的循环轻松解决这个问题,我喜欢这样的循环:

const string s = "A*A**B***A**";
string::size_type last_letter=-1, min_seq_len=s.size();
for(int i = 0; i < s.size(); i++) {
    if(last_letter == -1 || s[i] == '*' || s[i] == s[last_letter]) {
        if(s[i] != '*') {
            last_letter = i;
        }
    } else {
        min_seq_len = min(min_seq_len, i-last_letter-1);
        last_letter = i;
    }
}

但是,使用C ++ algorithms library,迭代器等有没有办法做到这一点?

我问这个问题是因为我注意到我无法学习如何使用这些设施来解决算法问题,而是我发现手工编写循环更容易。我想最终学习C ++算法,范围,迭代器等操作。

3 个答案:

答案 0 :(得分:0)

  

我对两个不同字母之间的星号序列感兴趣,特别是我需要找到最短序列的长度。

  1. 你需要尽量减少一些事情。您可以使用std::min_element

  2. 那是一堆&#34;字母+星号+字母&#34;块。您可以使用std::find_if

  3. 找到非星号

    然后你需要在算法之间写一些粘合剂,你可以隐藏在类似STL的界面后面。例如:

    auto letter_pairs = letter_pair_generator(s);
    const auto min_seq_len = std::min_element(
        std::begin(letter_pairs), std::end(letter_pairs),
        [](const auto& x) { return x.asterisk_count(); });
    

    其中letter_pair_generatorstd::string上的适配器,它暴露了一个类似于容器的接口,该接口返回两对不同字母,中间带有星号。例如:

    string s = "A*A**B***A**";
    for(const auto& p : letter_pair_generator(s)) cout << p;
    
      

    A * A **乙

         

    A **乙

         

    A ** ***乙A

         

    乙*** A

      

    相反,我发现手工编写循环更容易

    有时循环比对<algorithm>的多次调用更清晰,更快。这没有什么本质上的错误。使用循环并将其包装成更安全/更好的界面。

答案 1 :(得分:0)

我需要说使用标准库我无法获得巨大的改进。但是,例如std::regex示例如果没有明确的字母要求则会简单得多。无论如何,这是我的尝试。

  1. std::string::find_first_not_of用法

    int best = s.size();
    int prev = -1;
    int next;
    
    while ((next = s.find_first_not_of("*", prev+1)) >= 0) {
        if (prev >= 0 && s[prev] != s[next]) {
            best = min(best, next - prev - 1);              
        }
        prev = next;
    }  
    
  2. Runnable:https://ideone.com/xdhiQt

    1. std::regex用法:

      regex r("(?=([^*][*]*[^*]))");
      
      int best = s.size();
      for (auto i = sregex_iterator(s.begin(), s.end(), r); i != sregex_iterator(); ++i) {
          int pos = i->position(1);
          int len = i->length(1); 
          if (s[pos] != s[pos + len -1]) {
              best = min(len-2, best);
          }
      }   
      
    2. Runnable:https://ideone.com/2UdRGG

答案 2 :(得分:0)

您也可以find_first_not_of使用string

size_t min(str.length()), prev(0), found(0);
while((found = str.find_first_not_of("*", prev)) != std::string::npos) {
  if (str[found] != str[prev] && found - prev < min) {
    min = found + 1 - prev;
  }
  prev = found + 1;
}

demo