在 C++11 中,如何查找并返回以给定字符串开头的字符串向量中的所有项?
In C++11, how to find and return all the item(s) in a vector of strings that start with a given string?
(注意:当我提到向量时,我指的是<vector>
提供的vector
类。
问题所在
给定一个字符串x
和一个字符串向量,如何检索向量中以x
开头的字符串?最好以省时的方式?
也就是说,如果x
是"apple"
并且向量是vector<string> foods = {"apple pie","blueberry tarts","cherry cobbler"}
的,那么它应该以某种身份返回"apple pie"
。
我正在使用C++11,但我不是这方面的专家,所以简单的答案和解释将不胜感激。如果答案很明显,请原谅我 - 我对这门语言相对较新。
我考虑过的可能解决方案
显而易见的解决方案是创建一个迭代器并遍历向量中的每个字符串,使用具有pos
参数的重载版本的rfind
提取以给定字符串开头的所有项目。(也就是说,像这样:str.rfind("start",0)
(
但是,对于大向量,这在时间上效率低下,所以我想知道是否有更好的方法来做到这一点,即对向量进行排序并使用某种二叉搜索,或者也许从<algorithm>
修改find
方法?
复制所需字符串的最简单方法是简单的线性扫描。例如,使用标准库std::copy_if
执行复制,并使用 lambda 封装"开头为"字符串比较。
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
int main()
{
std::vector<std::string> foods = { "apple pie","blueberry tarts","cherry cobbler" };
std::string prefix{ "apple" };
auto starts_with = [&prefix](const std::string &str) {
return str.compare(0, prefix.size(), prefix) == 0;
};
std::vector<std::string> result;
std::copy_if(begin(foods), end(foods), back_inserter(result), starts_with);
for (const auto &str : result) {
std::cout << str << 'n';
}
}
解决问题的一个好方法是使用二叉搜索。请注意,这需要首先对strings
的vector
进行排序,这使算法的时间复杂度为NlogN
。
vector <string> v = {"a", "apple b", "apple c", "d"}; // stuff
string find = "apple";
// create a second vector that contains the substrings of the first vector
vector <pair<string, string>> v2;
for(string item : v){
v2.push_back({item.substr(0, find.size()), item});
}
sort(v2.begin(), v2.end());
// binary search to find the leftmost and rightmost occurrence of find
int l = v.size()-1, r = 0;
for(int i = v.size()/2; i >= 1; i /= 2){
while(l-i >= 0 && v2[l-i].first >= find){l -= i;}
while(r+i < v.size() && v2[r+i].first <= find){r += i;}
}
if(v2[l].first == find){
for(int i = l; i <= r; ++i){
cout << v2[i].second << endl;
}
}
else{
cout << "No matches were found." << endl;
}
在我的代码中,我们首先创建一个名为v2
的第二个vector
来存储strings
对。排序后,我们通过跳转实现二叉搜索,以找到find
的最左边和最右边的出现次数。最后,我们检查是否有任何出现(这是一个边缘情况(,并打印所有找到的strings
如果存在
您可以在向量上的单次传递中执行此操作。 除非对向量进行预排序,否则这是您最好的方法,因为排序的成本将超过使用二叉搜索获得的任何收益。
使用std::copy_if
使这变得非常简单:
#include <string>
#include <vector>
#include <algorithm>
int main() {
std::vector<std::string> v = {
"apple pie",
"blueberry tarts",
"apple",
"cherry cobbler",
"pie"
};
std::vector<std::string> v2;
std::string to_find = "apple";
std::copy_if(
v.begin(),
v.end(),
std::back_inserter(v2),
[&to_find](const std::string& el) {
return el.compare(0, to_find.size(), to_find) == 0;
}
);
}
现场演示
这会将v
中与谓词函数匹配的所有元素复制到v2
中。 谓词只是检查每个元素的前to_find.size()
个字符是否与要使用std::string::compare
查找的字符串匹配(该页面上的重载 (2((。
- 在 C++11 中,如何查找并返回以给定字符串开头的字符串向量中的所有项?
- 字符串开头的分隔符
- 如何使字符串出现在编译的二进制可执行文件的开头?
- 如何在 Arduino 字符串的开头添加元素.类似于 JS unshift();
- 为什么使用 QString::right 在字符串开头省略逗号?
- cout 切断 for 循环中的字符串开头
- 如何从字符串开头到第二个分隔符中提取子字符串?
- ZeroMQ (cppzmq) 订阅者,过滤器以相同的字符串开头
- 如何检查 std::vector<std::string> 的元素是否以某个子字符串开头?
- 如何在 qt 中使用 QRegularExpression 匹配字符串开头的空格?
- DeleteFile,以子字符串开头
- 是否有函数/WinAPI 可以判断一个字符串是否以不区分大小写的语言方式以另一个字符串开头?
- 检查一个字符串是否以另一个已知字符串开头
- 如何检查const char*是否以特定字符串开头?(C++)
- 字符串以某个字符串开头
- 如何清除字符串开头的垃圾
- 删除字符串c++开头和结尾的标点符号
- 检查字符串是否以另一个字符串开头:find或compare
- C++ std::map<std::string, int> 获取键以特定字符串开头的值
- c++ getline在字符串开头添加空格