これは完全にstd :: algorithmsで行うことができます。
概要:
すでにソートされていない場合、入力範囲を並べ替えます。ソートされた範囲 の最初と最後のパスは最も類似しません。最良の場合はO(N)、最悪の場合はO(N + N。logN個) 二つの最も異なる経路間larges共通の配列を決定する
使用std::mismatch
COUNTが最長共通の文字数である第一COUNT文字を消去する各パススルー[無意味]
ランシーケンス。 O(N)
ベストケースの時間計算量:O(2N)、最悪の場合O(2N + N.logN)(?誰かがそれを確認することができます)
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
std::string common_substring(const std::string& l, const std::string& r)
{
return std::string(l.begin(),
std::mismatch(l.begin(), l.end(),
r.begin(), r.end()).first);
}
std::string mutating_common_substring(std::vector<std::string>& range)
{
if (range.empty())
return std::string();
else
{
if (not std::is_sorted(range.begin(), range.end()))
std::sort(range.begin(), range.end());
return common_substring(range.front(), range.back());
}
}
std::vector<std::string> chop(std::vector<std::string> samples)
{
auto str = mutating_common_substring(samples);
for (auto& s : samples)
{
s.erase(s.begin(), std::next(s.begin(), str.size()));
}
return samples;
}
int main()
{
std::vector<std::string> samples = {
"/home/user/foo.txt",
"/home/user/bar.txt",
"/home/baz.txt"
};
samples = chop(std::move(samples));
for (auto& s : samples)
{
std::cout << s << std::endl;
}
}
が期待:
baz.txt
user/bar.txt
user/foo.txt
ここには、並べ替えを必要としない別の `common_substring 'があります。時間の複雑さは、理論のO(N)であるが、それは実際に速いのかどうか、あなたがチェックする必要があるだろう:
std::string common_substring(const std::vector<std::string>& range)
{
if (range.empty())
{
return {};
}
return std::accumulate(std::next(range.begin(), 1), range.end(), range.front(),
[](auto const& best, const auto& sample)
{
return common_substring(best, sample);
});
}
更新:
エレガンスはさておき、これはおそらく、それがいずれかを回避するので最速の方法ですすべての変換をインプレースで実行します。ほとんどのアーキテクチャとサンプルサイズでは、これは他のパフォーマンス上の考慮事項よりも重要です。
#include <iostream>
#include <vector>
#include <string>
void reduce_to_common(std::string& best, const std::string& sample)
{
best.erase(std::mismatch(best.begin(), best.end(),
sample.begin(), sample.end()).first,
best.end());
}
void remove_common_prefix(std::vector<std::string>& range)
{
if (range.size())
{
auto iter = range.begin();
auto best = *iter;
for (; ++iter != range.end() ;)
{
reduce_to_common(best, *iter);
}
auto prefix_length = best.size();
for (auto& s : range)
{
s.erase(s.begin(), std::next(s.begin(), prefix_length));
}
}
}
int main()
{
std::vector<std::string> samples = {
"/home/user/foo.txt",
"/home/user/bar.txt",
"/home/baz.txt"
};
remove_common_prefix(samples);
for (auto& s : samples)
{
std::cout << s << std::endl;
}
}
'/ home/user/martin、/ home/user/mike'を指定すると、結果は' artin、ike'または 'martin、mike'になりますか?あなたのタイトルは*文字列*と書かれていますが、あなたの質問にはパス名が記載されています。 –
私は誤解をおかけして申し訳ありません。両方の結果が大丈夫でしょう。もしどちらか一方が他よりもうまく実装できるなら、私はこの方が好きです – Exagon
どちらの結果もOKのユースケースは想像できません。 –