题目给出两个字符串str1和str2,要求判断用str1中的字符能否组合成str2。
限制条件是字符串都由小写字母组成。
要求考虑代码运行效率。
拿到题目第一反应就是遍历str2,然后查找str1,发现有匹配的字符就标记一下,继续后面的遍历,直到遍历完成代码如下:
bool scramble2(const char *str1, const char *str2)
{
/* solution here */
int i, k;
char * Src = str1;
char * Tar = str2;
char * Src_s;
k = strlen(Src);
Src_s = malloc(k);
memset(Src_s, 0, k);
while(*Tar)
{
for(i=0; Src[i]; i++)
{
if(Src[i] == *Tar && Src_s[i] == 0)
{
Src_s[i] = 1;
break;
}
}
if(Src[i] == '\0')
{
free(Src_s);
return false;
}
Tar++;
}
free(Src_s);
return true;
}
这样运行简单测试是通过了,但是正式提交的时候,12秒超时。。。通过加打印看,发现测试用例中有很多超长字符串(超过几万个字符),这样用遍历确实太慢了。后面想到字符串由26个字母组成,于是想到了建立一张表来存放各个字符出现的频次,于是重写代码如下:
bool scramble(const char *Src, const char *Tar)
{
/* solution here */
unsigned int SrcTbl[122] = {0};
unsigned int TarTbl[122] = {0};
unsigned int i, LenSrc, LenTar, Min, Max;
char * pchar = 0;
unsigned int * pTable = 0;
LenSrc = strlen(Src);
LenTar = strlen(Tar);
if(LenSrc > LenTar)
{
Min = LenTar;
Max = LenSrc;
pchar = Src;
pTable = SrcTbl;
}
else
{
Min = LenSrc;
Max = LenTar;
pchar = Tar;
pTable = TarTbl;
}
/*first, count the letters and store them in the table */
for(i=0; i<Min; i++)
{
SrcTbl[Src[i]]++;
TarTbl[Tar[i]]++;
}
for(i=Min ; i<Max; i++)
{
pTable[pchar[i]]++;
}
/*then, compare each element to determin if Src contains Tar */
for(i='a'; i<'z'; i++)
{
if(TarTbl[i] > SrcTbl[i])
{
return false;
}
}
return true;
}
这样运行测试,执行完成时间终于在12秒以内了。后面进一步我再想还能不能再优化一下,通过查询百度,发现strlen函数的实现原理也是要遍历一次字符串长度,这个比较耗费时间,于是又重新修改了下算法,不用strlen函数。算法如下:
bool scramble(const char *Src, const char *Tar)
{
/* solution here */
unsigned int SrcTbl[122] = {0};
unsigned int TarTbl[122] = {0};
unsigned int i;
char * pchar = 0;
unsigned int * pTable = 0;
/*first, count the letters and store them in the table */
for(i=0; Src[i] && Tar[i]; i++)
{
SrcTbl[Src[i]]++;
TarTbl[Tar[i]]++;
}
if(Src[i] != '\0')
{
pTable = SrcTbl;
pchar = Src;
}
else
{
pTable = TarTbl;
pchar = Tar;
}
while(pchar[i])
{
pTable[pchar[i]]++;
i++;
}
/*then, compare each element to determin if Src contains Tar */
for(i='a'; i<'z'; i++)
{
if(TarTbl[i] > SrcTbl[i])
{
return false;
}
}
return true;
}
这下自以为优化的比较好了,然而等我自信提交代码后,再看看人家的代码,瞬间被打击。。。人家代码是这样的:
bool scramble(const char *str1, const char *str2)
{
int count1[CHAR_MAX - CHAR_MIN + 1] = {0};
for (; *str1; ++str1) ++count1[*str1 - CHAR_MIN];
for (; *str2; ++str2)
if (--count1[*str2 - CHAR_MIN] < 0)
return false;
return true;
}
相比之下,自己感觉差距有点大。。。