[英]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.