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

How to find the shortest sequence of asterisks separating two distinct letters in a string using STL algorithms?

本文关键字:两个 算法 STL 何使用 字符串 分隔      更新时间:2023-10-16

我有一个这样的字符串:

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++算法库、迭代器等有什么方法可以做到这一点吗?

我问这个问题是因为我注意到我在学习如何使用这些工具来解决算法问题时遇到了困难,相反,我发现手工编写循环更容易。最后,我想学习C++算法、范围、迭代器等的操作。

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

  1. 您需要最小化某些内容。您可以使用std::min_element

  2. 这个东西是一堆"字母+星号+字母"块。使用std::find_if可以找到非星号。

然后你需要在算法之间写一些胶水,这样你就可以隐藏在类似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**B

A**B

A***B***A

B***A


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

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

您也可以使用string中的find_first_not_of

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;
}

演示

我需要说的是,使用标准库并不能带来巨大的改进。但以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;
    }  
    

可跑步: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);
    }
    }   
    

可跑步:https://ideone.com/2UdRGG