您的位置:首页 > 职场人生

算法-美团2015校招笔试:写一个复杂度为n的排序算法

2015-07-29 00:00 483 查看
一组随机排序的字母数字。请编写一个时间复杂度为O(n)的算法,使这些字母从小到大顺序排序。
说明:字母区分大小写,相同的字母,排序护小写排在前面。
例如:R,B,B,b,W,W,B,R,B,w
排序为:b,B,B,B,B,R,R,w,W,W

#include <stdio.h>
#include <string.h>
void getHelper();
int main() {
char str[100];
int helper[150]={0};
int i,j;
gets(str);
getHelper(str, helper);//复杂度为O(n)
for(i = 'a'; i <='z' ; i++) {//复杂度接近为O(1)
if(helper[i] > 0) {
for(j= 0;j < helper[i] ; j++){
printf("%c",i);
}
if(helper[i-32] >0) {
for(j= 0;j < helper[i-32] ; j++){
printf("%c",i-32);
}
}
}else if(helper[i-32] > 0){
for(j= 0;j < helper[i-32] ; j++){
printf("%c",i-32);
}
}
}
return 0;
}
void getHelper(char *p,int helper[]){
int i, len;
len = strlen(p);
for (i = 0; i < len; i++) {
helper[p[i]]++; /*将当前字符所对应的ASCII码作为helper数组的下标,同时加1*/
}

}

这个是昨天写的,由于时间就比较晚了,没有做任何的解析,今天就做些说明,一方面自己当做笔记,日后可以翻阅,另一方面,帮助一些不太了解这个算法的同学们。

好了,废话不多说,现在开始:

先抛开这个这个题目的其他条件不看,仅仅看“写一个复杂度为O(n)的排序算法”,这个条件一定吓退了不少人,因为就目前来看,速度最快的算法也不过O(nlog(n)),怎么可能有O(n)的算法,所以从这里看,这个题目就不是考基础算法的,需要你动脑筋,根据条件,写一个算法的。

对于解决这个问题,我先告诉大家解决这类问题的方法,稍后再做解释:

如果是对于数字类型的排序,前提是这些数字是有范围(这个范围是很重要的前提,如果没有这个范围,该方法是失效的),可以新建一个数组(helper[]),可以通过变量所给数组(array[]),把所给数组的值作为helper[]的下标,该下标所对应的值为就是遍历到元素的个数;说的比较抽象,实在想不到再简单的语言了,我就用代码解释吧,看下面的代码:

void getHelper(char *array,int helper[]){
int i,len;
len = strlen(array);
for(i = 0 ; i < len; i ++) {/*遍历的是所给的数组,而不是helper数组*/
helper[array[i]]++; /*将对应的元素的下标+1*/
}
/*所以,我们可以把helper数组理解为一个计数器,就是记录所给数组元素的个数*/
}

这个helper数组非常重要,有了它稍后的操作就会变的很快,有点KMP的next数组的意思,但是他们的用法是不一样的。

有了这个helper数组,就可以指导我们去排序了,先贴代码吧:

void sort(int helper[]) {
int i,j;
for(i='a' ; i < 'z'; i++) {/*这一步遍历的范围就是我一开始提到的,这个题目的范围,其目的就是遍历helper的存储的数据*/
if(helper[i] > 0) {
for(j = 0 ; j < helper[i] ; j++) {
printf("%c",i);
}
}
}
}

通过上述的算法,你就已经可以排序“如果存在一个随机串,从a->z,写一个O(n)算法,对他们进行排序”,对于我们今天要解决的这道题,只是添加了小小的附加条件,就是"区分大小写,并且相同字母小写在前"。直接贴代码:

其实只需修改一下sort()方法就可以了:

void sort(int helper[]){
for(i = 'a'; i <='z' ; i++) {
if(helper[i] > 0) {
for(j= 0;j < helper[i] ; j++){
printf("%c",i);
}
helper[i] = 0;
if(helper[i-32] >0) {
for(j= 0;j < helper[i-32] ; j++){
printf("%c",i-32);
}
}
helper[i-32] = 0
}else if(helper[i-32] > 0){
for(j= 0;j < helper[i-32] ; j++){
printf("%c",i-32);
}
}
}
}

下面对上述代码,做些解释:

上述我们所讲的范围是从A->z,你为什么用a->z呢?

首先我们知道,大小写之间的ASCII码值相差32,所以我们知道了小写字母,同时也就知道了大写字母,其中helper[i-32]就是代表的对应的大写字母,所以我们就不需要在遍历A->Z的部分。

好了,其实理解的话这个算法也是很好理解的,非常感激某位博友,非常抱歉我忘记了你的博客站,是你的文章给了我启发。在此对你表示感谢,以后能找的话,我再贴到此处。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  O(n)排序 面试题