1.昨天(10月10日)腾讯一面,一道简单的面试题,本以为写得还不错,结果今天回来仔细思考并coding,发现此程序中漏洞多多。
2.题意:删除一个字符串中重复出现的字符,只留下第一次出现的字符。如:输入abaacdba,输出abcd。
3.思路:定义一个数组来存放每个字符出现的次数,如果发现字符已经出现,则删除该字符。
4.代码:
(1)当时写的版本:
char* DeleteFun(char* str)
{
int times[WordNumber];
for (int i = 0; i < WordNumber; i++)
{
times[i] = 0;
}
char* p = str;
int index;
while (*p != '\0')
{
index = *p - 'a';
if (times[index] == 0)
{
times[index]++;
}
p++;
}
p = str;
char* ret = str;
while (*p != '\0')
{
index = *p - 'a';
if (times[index] != 0)
{
times[index] = 0;
*ret = *p;
ret++;
}
p++;
}
ret++;
*ret = '\0';
return str;
}
(2)当时检查了一遍,发现没有加 *ret = '\0'这一句,加上之后自以为还比较满意。
5.回来发现的问题
(1)最后ret++是多余的,有错的,加了这一句会多一个字符;
(2)时间花费了2*N,开销有点大;
(3)这里只考虑了26个小写字母,而没有考虑大写字母和特殊字符。
6.刚刚仔细想想,并且在与kk同学的讨论中,把程序改进了一下,如下:
char* DeleteFun1(char* str)
{
int times[256];
//memset(times, 0, 256 * sizeof(int));
memset(times, 0, sizeof(times));
char *p = str;
char *q = str;
while (*p != '\0')
{
if (times[*p] != 0)
{
p++;
}
else
{
times[*p] = 1;
*q = *p;
p++;
q++;
}
}
*q = '\0';
return str;
}
几点思考:
(1)出现次数数组大小为256,可以容纳所有的大小写字母和特殊字符;
(2)初始化使用memset,比用for循环效率高,而且写得更简单;
(3)只要用一个循环即可,即扫描的时候即判断这个字符是否是出现了,如果没有出现则留下这个字符,如果已经出现了则直接pass掉;
(4)不用加index这个变量,也不用做操作*p - 'a',可以直接用*p来作下标(因为开了256大小的数组);
(5)sizeof(times)的大小和256 * sizeof(int)的大小是一样的。