算法-美团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的部分。
好了,其实理解的话这个算法也是很好理解的,非常感激某位博友,非常抱歉我忘记了你的博客站,是你的文章给了我启发。在此对你表示感谢,以后能找的话,我再贴到此处。
相关文章推荐
- 一个关于if else容易迷惑的问题
- 一道sql面试题附答案
- C# 超高面试题收集整理
- 人人网javascript面试题 可以提前实现下
- PHP中设置一个严格30分钟过期Session面试题的4种答案
- 据说是雅虎的一份PHP面试题附答案
- php牛逼的面试题分享
- 一套比较完整的javascript面试题(部分答案)
- 小米公司JavaScript面试题
- 超级全面的PHP面试题整理集合第1/2页
- 5个实用的shell脚本面试题和答案
- PHP经典面试题集锦
- 8个PHP数组面试题
- PHP中提问频率最高的11个面试题和答案
- 用PHP解决的一个栈的面试题
- 几道坑人的PHP面试题 试试看看你会不会也中招
- 5个JavaScript经典面试题
- Java高级面试题小结
- 探讨Java中最常见的十道面试题(超经典)
- 15个高级Java多线程面试题及回答