我最近加入一个算法协会,这是其中的每日一题中的一例,感觉比较有意思,其想法也和平常大学中作业习题中的想法有较大区别,其中我也参考了一些网上的做法,在这里将自己的总结心得体会记录下来,以供参考 。
基本问题是这个样子的:
1.给出一串单词,让你将其中的组成字母相同的单词(移位词)放到一起,并且输出。
2.按照字典序输出。
这个题由于我目前C语言能力还不太够,也就是说字典序输出存在一些问题,故没有实现,但是将移位词分类并且集中到一起的方法确实非常有意思,我决定将自己的理解分享出来,这个题看似很简单,大多数人的第一想法肯定是逐个字符判断,并且将其记录下来,在和后面的进行比较,可是这样你想,每个单词都需要比较,而且假若这个单词较长,或者是数据量很长,那样岂不是花费大量的时间,而且准确率也不能做出保证,这里我想到的一种解决方法是这样的:
1.如果两个单词是移位词,那么他们必然会有相同得字母组成,也就是说将他们的逐个字母拆出来,按照ASC码的顺序排序,形成的字符串,必然是相同得,这就是给了这个单词一个标志,标志相同得必然是移位词,所以我们必然要给出另外一个字符数组来存放这个单词的标志。
2.有了这个标志,我们要考虑的是怎样将拥有同样的标志的单词放到一起,联想到将一些带有某些相同性质的东西聚集到一起,我们想到的肯定是排序,也就是将这些带有标志的单词排序,即我们要将这些标志字符串排序,将相同标志的放到一起,这样就可以将他们集中起来。
3。对于输出问题,我觉得仍然会有人疑惑,集中起来了怎样分开输出呢?这里也是我所疑惑的地方,脑子当时比较卡壳,去网上搜了一下,发现了一种方法,就是既然有了标志 ,就以标志作为分界,最开始先给一个字符串STRCPY成为排序为第一个的单词的标志,然后循环进行判断,如果标志相同,就输出,标志不同,将字符串重新赋值成新的标志然后输出一个换行符,继续输出,这样在输出上看起来就会使分层的了。(代码在最后部分)
接下来就是对数字快排的拓展应用字符串快排以及字符快排的详解
跟数字快排相同得的是,判断条件几乎一样,只是需要替换的内容变化了,但是其中和数字快排一样有一些小细节需要注意
void kuaipai(char s[],int left,int right)//此函数是将一个单词按照ASC码顺序进行重排,作为输入单词的标志使用。
{
char ch;
int l,r;
//上面三个变量就是对于常见的数字快排做了一次字符快排的本地化改变,与普通快排并无太大差异。
l=left;
r=right;
ch=s[l];
if(l>=r)
{
return;
}
else
{
while(l<r)
{
while(s[r]>ch&&l<r)
{
r--;
}
if(l<r)
{
s[l]=s[r];
l++;
}
while(s[l]<=ch&&l<r)
{
l++;
}
if(l<r)
{
s[r]=s[l];
r--;
}
}
}
s[l]=ch;
kuaipai(s,left,l-1);
kuaipai(s,l+1,right);
}
这是对字符进行了一下快排,可以看出的是在执行while循环的时候里面的条件需要着重判断,对于等号的取舍问题,一定要搞明白,同理字符串排序也是如此,但是字符串排序跟其不同的是,在判断的时候,你没有办法直接判断,只能调用STRCMP进行判断,这个函数里面需要放入两个字符串,如果第一个大于第二个,返回正数,小于返回负数,等于则返回0;同理对于字符串的赋值,也不能直接赋值,这个想必大家都懂,需要调用STRCPY来执行这个操作。
#include<stdio.h>
#include<string.h>
void kuaipai(char s[],int left,int right)//此函数是将一个单词按照ASC码顺序进行重排,作为输入单词的标志使用。
{
char ch;
int l,r;
//上面三个变量就是对于常见的数字快排做了一次字符快排的本地化改变,与普通快排并无太大差异。
l=left;
r=right;
ch=s[l];
if(l>=r)
{
return;
}
else
{
while(l<r)
{
while(s[r]>=ch&&l<r)
{
r--;
}
if(l<r)
{
s[l]=s[r];
l++;
}
while(s[l]<=ch&&l<r)
{
l++;
}
if(l<r)
{
s[r]=s[l];
r--;
}
}
}
s[l]=ch;
kuaipai(s,left,l-1);
kuaipai(s,l+1,right);
}
void sort(char s[])//这个函数也是就是调用一个上面那个函数排序。
{
int i;
i=strlen(s);
kuaipai(s,0,i-1);
}
void biaozhihanshu(char danci[][30],char xinhao[][30],int length)//调用上面的两个排序函数实现标志的录入
{
int i;
char s[30];
for(i=0;i<length;i++)
{
strcpy(s,danci[i]);
sort(s);
strcpy(xinhao[i],s);
}
}
void zifushuzupaixu(char danci[][30],char xinhao[][30],int left,int right)//这是对一个字符串进行快排
{
int l=left,r=right;
char sd[30];
char sx[30];
strcpy(sd,danci[left]);
strcpy(sx,xinhao[left]);
if(l>=r)
{
return;
}
else if(r-1==1)
{
if(strcmp(sx,xinhao[r])<0)
{
return;
}
else
{
strcpy(xinhao[l],xinhao[r]);
strcpy(danci[l],danci[r]);
strcpy(danci[r],sd);
strcpy(xinhao[r],sx);
}
}
else
{
while(l<r)
{
if(strcmp(sx,xinhao[r])<0&&l<r)
{
r--;
}
if(l<r)
{
strcpy(danci[l],danci[r]);
strcpy(xinhao[l],xinhao[r]);
l++;
}
if(strcmp(sx,xinhao[l])>=0&&l<r)
{
l++;
}
if(l<r)
{
strcpy(danci[r],danci[l]);
strcpy(xinhao[r],xinhao[l]);
r--;
}
}
strcpy(danci[l],sd);
strcpy(xinhao[l],sx);
zifushuzupaixu(danci,xinhao,left,l-1);
zifushuzupaixu(danci,xinhao,l+1,right);
}
}
void guileizhengli(char danci[][30],char xinhao[][30],int length)//这是上面所说的归类整理的函数
{
char sx[30];
strcpy(sx,xinhao[0]);
for(int i=0;i<length;i++)
{
if(strcmp(sx,xinhao[i])!=0)
{
strcpy(sx,xinhao[i]);
printf("\n%s ",danci[i]);
}
else
{
printf("%s ",danci[i]);
}
}
}
int main()
{
char danci[5][30]={"eat","tea","tan","ate","bat"};
char xinhao[5][30];
biaozhihanshu(danci,xinhao,5);
zifushuzupaixu(danci,xinhao,0,4);
guileizhengli(danci,xinhao,5);
return 0;
}
P.S对于代码的其中有个莫名其妙的小BUG就是对于字符串快排时,会出现前两个排序颠倒这种情况,但是其他位置并无这种问题,我的解决方案的是对于只剩下两个的时候进行一次判断,但是我始终觉得代码里面藏着一个我找不出来的小BUG,希望有人看出来后回复指正我一下