我的作业是在随机字符串中删除重复项。我的想法是用两个循环来解决这个问题。
第一个将扫描字符串中的每个字符。第二个将检查字符是否重复。如果是,删除该字符。
string content = "Blah blah..."
for (int i = 0; i < content.size(); ++i) {
char check = content.at(i);
for (int j = i + 1; j < content.size() - 1; ++j) {
if (check == content.at(j)) {
content.erase(content.begin()+j);
}
}
}
问题是它不起作用。它总是删除错误的字符。似乎是索引问题,但我不明白为什么。
临时修复是将content.erase(content.begin()+j);
更改为content.erase( remove(content.begin() + i+1, content.end(), check),content.end());
但我认为触发"按值删除"扫描不是一个好方法。我想用2个或更少的循环来完成。
你的循环可以像这样
#include <iostream>
#include <string>
int main()
{
std::string s = "Blah blah...";
std::cout << '"' << s << '"' << std::endl;
for ( std::string::size_type i = 0; i < s.size(); i++ )
{
std::string::size_type j = i + 1;
while ( j < s.size() )
{
if ( s[i] == s[j] )
{
s.erase( j, 1 );
}
else
{
++j;
}
}
}
std::cout << '"' << s << '"' << std::endl;
return 0;
}
输出为
"Blah blah..."
"Blah b."
还有许多其他使用标准算法的方法。例如
#include <iostream>
#include <string>
#include <algorithm>
#include <iterator>
int main()
{
std::string s = "Blah blah...";
std::cout << '"' << s << '"' << std::endl;
auto last = s.end();
for ( auto first = s.begin(); first != last; ++first )
{
last = std::remove( std::next( first ), last, *first );
}
s.erase( last, s.end() );
std::cout << '"' << s << '"' << std::endl;
return 0;
}
输出与前面的代码示例
相同"Blah blah..."
"Blah b."
如果可以选择使用STL,则可以使用std::unordered_set
来保留到目前为止看到的字符,并使用std::remove_if
的擦除-删除习惯用法,如下面的示例所示:
#include <iostream>
#include <string>
#include <unordered_set>
#include <algorithm>
int main() {
std::string str("Hello World!");
std::unordered_set<char> log;
std::cout << "Before: " << str << std::endl;
str.erase(std::remove_if(str.begin(), str.end(), [&] (char const c) { return !(log.insert(c).second); }), str.end());
std::cout << "After: " << str << std::endl;
}
现场演示
我建议采用两步方法。第一次传递识别重复字符的位置;第二遍删除它们。
我建议使用std::set
和std::vector<unsigned int>
。vector包含字符串中的字母。向量包含重复字母的位置。第一次遍历检测字母是否出现在集合中。如果该字母存在,则将该位置添加到vector。否则,将字母插入集合中。
对于第二次遍历,按降序对vector进行排序。
擦除矢量中位置处的字符,然后从矢量中删除该位置。
通过从字符串末尾向前面擦除字符,当该字符从字符串中擦除时,其余重复项的位置不会改变。
我不确定这是什么导致你的问题,但另一个问题,我看到你的代码是在你的第二个for循环。您的j < content.size() - 1
语句应该只是
j < content.size()
。
这样做的原因一开始看起来有点棘手,但在这种情况下,你不仅仅是让向量的大小作为大小,而是作为字符串的结束索引。你将最后一个下标缩短了一个,这意味着你不会击中字符串中的最后一个字符。我不知道这是否能帮助你解决最初的问题,但谁知道呢?
注意:您的实际问题是维护下一个元素的适当索引:
- 如果不擦除字符,则下一个元素将位于下一个位置。
- 如果你擦除一个字符,下一个元素将移动到当前位置(位置保持不变)。
还有:有更有效的解决方案(例如:
排序优先
则unique
将所有唯一字符移到开头,并返回经过结束的迭代器。
然后erase
无用的字符
string digits("1a2b3c3c2b1a");
sort(digits.begin(), digits.end());
digits.erase( unique( digits.begin(), digits.end() ), digits.end() );
cout << digits << endl;
输出123abc