![](/img/trans.png)
[英]Efficient (time and space complexity) data structure for dense and sparse matrix
[英]Removing specified characters from a string - Efficient methods (time and space complexity)
这是问题所在:从给定的字符串中删除指定的字符。
Input: The string is "Hello World!" and characters to be deleted are "lor"
Output: "He Wd!"
解决这个问题涉及两个子部分:
为了解决第一部分,我正在读取要删除的字符到std::unordered_map
,即,我解析字符串“ lor”并将每个字符插入到哈希图中。 稍后,当我解析主字符串时,我将使用每个字符作为键查看此哈希图,如果返回的值非零,则将从字符串中删除该字符。
问题1:这是最好的方法吗?
问题2:哪个对这个问题更好? std::map
或std::unordered_map
吗? 由于我对订购不感兴趣,因此我使用了unordered_map
。 但是创建哈希表是否有更高的开销? 在这种情况下该怎么办? 使用map
(平衡树)还是unordered_map
(哈希表)?
现在进入下一部分,即从字符串中删除字符。 一种方法是删除字符并将数据从该点开始移回一个位置。 在最坏的情况下,我们必须删除所有字符,这将花费O(n ^ 2)。
第二种方法是仅将所需的字符复制到另一个缓冲区。 这将涉及分配足够的内存来容纳原始字符串,并逐个字符地进行复制,而忽略要删除的字符串。 尽管这需要额外的内存,但这将是O(n)操作。
第三种方法是从第0个位置开始读取和写入,每次读取时增加源指针,仅在写入时增加目标指针。 由于源指针将始终与目标指针相同或位于目标指针之前,因此我可以在同一缓冲区上进行写操作。 这样可以节省内存,并且也是O(n)操作。 我在做同样的事情,并在最后调用resize
来删除其他不必要的字符?
这是我编写的函数:
// str contains the string (Hello World!)
// chars contains the characters to be deleted (lor)
void remove_chars(string& str, const string& chars)
{
unordered_map<char, int> chars_map;
for(string::size_type i = 0; i < chars.size(); ++i)
chars_map[chars[i]] = 1;
string::size_type i = 0; // source
string::size_type j = 0; // destination
while(i < str.size())
{
if(chars_map[str[i]] != 0)
++i;
else
{
str[j] = str[i];
++i;
++j;
}
}
str.resize(j);
}
问题3:我可以通过哪些不同方式来改善此功能。 还是我们能做到的最好?
谢谢!
做得好,现在了解标准库算法并提高:
str.erase(std::remove_if(str.begin(), str.end(), boost::is_any_of("lor")), str.end());
假设您正在研究算法,并且对库解决方案不感兴趣:
当可能的密钥数量很大时,哈希表最有价值,但是您只需要存储其中的几个即可。 如果要从数字序列中删除特定的32位整数,则哈希表将很有意义。 但是,对于ASCII字符,这是太过分了。
只需制作一个256个布尔数组,并为要删除的字符设置一个标志。 每个输入字符仅使用一个查表指令。 哈希映射至少涉及一些其他指令来计算哈希函数。 在空间上,一旦将所有辅助数据加起来,它们可能不再紧凑。
void remove_chars(string& str, const string& chars)
{
// set up the look-up table
std::vector<bool> discard(256, false);
for (int i = 0; i < chars.size(); ++i)
{
discard[chars[i]] = true;
}
for (int j = 0; j < str.size(); ++j)
{
if (discard[str[j]])
{
// do something, depending on your storage choice
}
}
}
关于存储选项:根据是否需要保留输入数据,在选项2和3之间进行选择。 3显然是最有效的,但是您并不总是需要就地过程。
这是具有许多优势的KISS解决方案:
void remove_chars (char *dest, const char *src, const char *excludes)
{
do {
if (!strchr (excludes, *src))
*dest++ = *src;
} while (*src++);
*dest = '\000';
}
您可以在strcspn
和strspn
之间strcspn
乒乓strcspn
,以避免需要哈希表:
void remove_chars(
const char *input,
char *output,
const char *characters)
{
const char *next_input= input;
char *next_output= output;
while (*next_input!='\0')
{
int copy_length= strspn(next_input, characters);
memcpy(next_output, next_input, copy_length);
next_output+= copy_length;
next_input+= copy_length;
next_input+= strcspn(next_input, characters);
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.