例如,给定一个“ Stackoverflow是为每一个 ”并删除“aeiou”, 该函数应将str转换为“ Stckvrflw s fr v n n ”。
我有一个字符串的char数组: str [] 和一个要删除的字符char数组:删除[]
我的解决方案:循环str []在remove []中查找每个字符。每次都移动str []一个地方。我相信更好的黑客是可能的。
答案 0 :(得分:5)
将整个字符串向左移动一个位置将有效地使其成为O(n ^ 2)算法。您可以在线性时间内就地执行此操作:
void Remove (char * src, const char * match) {
char * dest = src;
for (;;) {
char ch = *src++;
if (!strchr (match, ch)) *dest++ = ch; // Copy chars that don't match
if (!ch) break; // Stop when we copy over a null
}
}
我在这里假设这些是空终止的。如果不是这种情况,那么您也必须传入长度并适当地修改算法。特别是,您将无法使用strchr。为了完整起见,这里有一个与char数组一起使用的版本(不是以null结尾)。
// Removes from str[] (of length strlen), all chars that are found
// in match[] (of length matchlen). Modifies str in place, and returns
// the updated (shortened) length of str.
int Remove (char[] str, int srclen, char[] match, int matchlen) {
int dst = 0, found;
for (int src = 0; src < srclen; src++) {
char ch = str[src];
found = 0; // Search if this char is found in match
for (int i = 0; i < matchlen && !found; i++)
if (match[i] == ch) found = 1;
if (!found) str[dst++] = ch;
}
return dst;
}
最后,我认为这与我们将要获得的O(n)接近。我在这里假设8位字符并构建一个查找表,因此这应该在O(n)+ O(m)中运行,其中m是匹配字符串的长度。
int Remove (char* str, int srclen, char* match, int matchlen) {
bool found[256];
for (int i = 0; i < 256; i++) found[i] = 0;
for (int i = 0; i < matchlen; i++) found[match[i]] = 1;
int dst = 0;
for (int src = 0; src < srclen; src++) {
char ch = str[src];
if (!found[ch]) str[dst++] = ch;
}
return dst;
}
答案 1 :(得分:2)
我相信这是“经典”谜题之一。
实质上,您扫描'match'字符串并创建可能匹配的查找位表。
然后你走过'src'一次,检查你桌子上的每个字符。
O(n)时间。
类似这样的算法:
static char bits[32]; // Not thread-safe, but avoids extra stack allocation
char * dest = src;
memset(bits, sizeof(bits), 0);
for (; *remove; remove++)
{
bitfields[*match >> 3] |= *remove & 7;
}
for (;*src; src++)
{
if (!((bits[*src >> 3] & (*src & 7)) == (*src & 7)))
{
*dest++ = *src;
}
}
我相信ischr(),isdigit(),isspace()等与此技术类似,但它们的查找表是不变的。
答案 2 :(得分:2)
这是我的版本,if
语句从复制循环中删除:
#include <stdio.h>
#include <string.h>
int main( void ){
unsigned char str[] = "Stackoverflow is for every one";
unsigned char remove[] = "aeiou";
unsigned char table[256] = { [ 0 ... 255 ] = 1 };
for( unsigned char *r=remove; *r; r++ ){ table[*r]=0; }
unsigned char *source=str, *dest=str;
while( (*dest = *source++) ) dest += table[*dest];
printf( "str: '%s'\n", str );
}
答案 3 :(得分:0)
如果你能再买一个缓冲区,你可以: 循环str []在remove []中查找每个字符,但不是shift,而是复制到新数组。
答案 4 :(得分:-1)
我会循环str []并将remove []中不存在的每个字符存储在一个新数组中(比如说new_str [])。然后用str []交换new_str []。
答案 5 :(得分:-1)
使用正则表达式查找和替换是一种更紧凑的解决方案。使用GNU C库或找到支持正则表达式搜索和替换的另一个库。当然,如果每次都有不同的字符,则必须在运行时创建正则表达式。如果您坚持使用当前的方法,请将其拆分为函数。
我也喜欢Tarydon的做法。它的工作少了!!