【问题标题】:Checking if a character occurs at least N times in the string. Any solution in algorithms?检查一个字符是否在字符串中至少出现 N 次。算法中的任何解决方案?
【发布时间】:2020-12-03 15:05:22
【问题描述】:

这个问题在得到解决方案方面并不难,但我想知道是否有任何 C++ 函数或算法可以解决它。

我在处理这个问题时想到了这个想法Count character occurrences in a string in C++

所以想知道除了从头开始编写一个函数来检查字符串中是否存在特定数量的字符之外,我们是否还有其他选择。 例如让我们说:

std::string s = "a_b_c_d_e_f_g_h_i_j_k_l_m";

并且我们要查找字符串中是否至少有2个'_'。 如果我们使用std::count,它将返回所有“_”的计数。 std::count_if 也将以类似的方式运行。 我可以编写代码来循环遍历字符串并在计数达到 2 时立即中断,但我想知道我们是否有一些现有的 C++ 算法或函数解决方案。

这里的思考过程是,如果我们得到一个很长的字符串作为输入,并且做某事的标准是基于特定字符是否至少出现n次,那么遍历整个是一种浪费字符串。

【问题讨论】:

  • 为什么不简单地类似于std::map<char, int> counts; for (auto c : the_string) { counts[c]++; }
  • @JesperJuhl 他想避免检查完整的字符串
  • 这不是 OP 的问题,他想尽早终止循环以避免在知道后使用 cpu 周期;完成
  • @Makogan Fine;然后检查循环中的计数和break; 是否高于阈值。
  • @novice 您可以轻松检查<algorithm>中的可用内容。

标签: c++ string algorithm stl


【解决方案1】:

使用c++20,可以编写如下函数:

namespace sr = std::ranges;
namespace sv = std::ranges::views;

bool has_count_elements(auto&& range, int count, auto elem)
{
    auto match = [=] (auto c) { return c == elem; };

    auto matches = sv::filter(range, match) | sv::drop(count - 1);

    return not sr::empty(matches);
}

并像这样使用它:

int main() 
{
    std::string s = "a_b_c_d_e_f_g_h_i_j_k_l_m";
    std::cout << has_count_elements(s, 2, '_');   // prints 1
} 

由于filterview 懒惰地评估范围,即仅根据需要进行评估,因此函数将在找到count 元素后返回,并且beginend 在评估sr::empty 时不同.

此外,您应该限制函数,使elem 具有与range 的基础类型相同的类型。

这是demo


我确定我已经在 SO 上的某个地方看到过这个问题和这个答案,但我似乎找不到它。

【讨论】:

  • 对c++20不太了解,能不能解释一下它是如何工作的?
【解决方案2】:

std::find_if 使用适当的函子就可以完成这项工作:

std::string s1 = "a_b_c_d_e_f_g_h_i_j_k_l_m";
int count = 0;
bool found =
    std::find_if(s1.begin(), s1.end(),
        [&count] (char c) {
           return c == '_' && ++count == 2;
        }) != s1.end();

不过,我更愿意为此创建一个新函数,我们称之为find_if_n

template<typename Iterator, typename Predicate>
Iterator find_if_n(Iterator begin, Iterator end, Predicate&& pred, int n) {
    return std::find_if(begin, end,
                          [&pred, &n] (const auto& v) {
                             return pred(v) && --n == 0;
                          });
}

更简单的用法:

bool found = find_if_n(s1.begin(), s1.end(), [] (char c) {
                  return c == '_';
             }, 2) != s1.end();

【讨论】:

    【解决方案3】:

    一种可能的解决方案是使用std::all_of(),因为当谓词为false 时此函数停止:

    #include <iostream>
    #include <string>
    #include <algorithm>
    
    int main()
    {
        std::string str = "a_b_c_d_e_f_g_h_i_j_k_l_m";
        char search = '_';
        int count = 0, limit = 2;
        
        std::all_of(str.begin(), str.end(), [&search, &count, &limit](const char& c){
            std::cout << c << " ";
            if (c == search){
                count++;
            }
            return count < limit;
        });
        
        std::cout << "\nContains at least " 
        << limit << " " << "'" << search << "' ? " << count 
        << std::endl;
    }
    

    因此,只要您的谓词错误,您就可以浏览您的字符串。
    在这种情况下,您只需检查 4 个字符来代替完整的字符串: a _ b _

    【讨论】:

    • 如果string 真的非常大(意思是真的),通过使用std::atomic&lt;int&gt; count;std::all_of(std::execution::par, ...,这种新颖的方法也许可以运行得非常快。由于它不必将迭代器返回到第二个匹配项,因此允许提前返回。
    【解决方案4】:

    您可以使用例如std::find_if。你来了

    #include <iostream>
    #include <string>
    #include <iterator>
    #include <algorithm>
    
    int main() 
    {
        std::string s = "a_b_c_d_e_f_g_h_i_j_k_l_m";
        
        std::string::size_type n = 0;
        
        auto it = std::find_if( std::begin( s ), std::end( s ),
                                 [&n]( const auto &c )
                                 {
                                     return c == '_' && ++n == 2;
                                 } );
                       
        std::cout << std::distance( std::begin( s ), it ) << '\n';                 
                           
        return 0;
    }
    

    程序输出是

    3
    

    即算法在找到第二个字符“_”后立即停止执行。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多