算法面试小结

1. 求一个数转化为二进制后,包含1的数量

int func(int x)
{
    int count = 0;
    while(x)
    {
        count ++;
        x = x & (x - 1);
    {
    return count;
}

2. 求平均值

int func(int x, int y)
{
    return (x & y) + ((x^y)>>1);
}

解析:x&y是取相同位与,结果是x和y相同位的和的一半;x^y是取x和y的不同位,右移相当于除以2,所以这个函数的功能是取平均值

3. 有1千万条短信,有重复,以文本的形式保存,一行一条,有重复。请用5分钟的时间,找出重复出现最多的前10条。

  • 方法一hashTable
1. 分组,边扫描边建散列表
2. 第一次扫描,取首尾字符,中间随便两字节作为Hash Code,插入hash table,记录其地址和信息长度和重复次数;同hash code且等长即疑似相同。相同记录只加1次进hash table,将重复次数加1。
3. 第一次扫描已经记录各自的重复次数,扫描第二次,用线性时间可在O(n)级别上完成前10条寻找
4. 分组后每份中的top10必须保证各不相同,可hash保证,也可直接按hash值的大小来分类
  • 方法二排序
1. 除非群发,一般字数越少,越有可能。先从1字、2字的开始统计,找出各自top10
2. 对于字数长的,除了用hash,还可以用首尾和中间字节,可以加快查询速度,但未必准确,需要标记
3. 遍历各组的top10,寻找备选top10,遇到标记,则统计相同字数下的短信,精确找出真正的top10
  • 方法三内存映射——待深入理解
1. 可以采用内存映射文件(文件过大,可以分段映射)
2. 对每条短信的第i(i从0到70)个字母按照ASCII进行分组,就是创建树,i是树的深度,也是短信第i个字母

4. 1亿个浮点数,请找出最大的1万个

假设每个浮点数占4个字节,1亿个浮点就要占有相当大的空间。

  • 阈值过滤
先读出100万个数据,找出最大的1万个,如果数据理想,那么以1万个数据里面最小的为基准,可以过滤掉1亿数据里面99%的数据
最后在剩下的100万里找出最大的1万个。
  • 分块查找
100万一个块,分别找出最大的1万个,筛选出100万个
采用快速排序方法,分2堆,如果大的那个堆的个数N大于1万个,继续对大堆快排一次分成2堆,如果大堆个数N小于1万,就在小的那堆里面快排一次,找出第10000-N大的数字。递归以上过程

5. 排序

  • 排序的稳定性

待排序记录相同时,经过排序后具有相同关键字的记录之间的相对次序保持不变,则是稳定的。

  • 分类

内外存交换:若在排序过程中,整个文件都是放在内存中,排序时不涉及数据的内、外存交换,则称为内部排序,否则是外部排序;前者适合记录个数不多的小文件

策略:插入排序、选择排序、交换排序、归并排序、分配排序

快速排序

采用了分治法的思想

快排是一种不稳定的排序方法,平均时间复杂度为O(nlogn),最差时间复杂度为O(n^2)

void QuickSort(SeqList R, int low, int high)
{
    int privotpos;
    if (low < high)
    {
        privotpos = Partition(R, low, high);
        QuickSort(R, low, privotpos-1);
        QuickSort(R, privotpos+1, high);
    }
}
int Partition(SeqList R, int i, int j)
{
    ReceType pivot = R[i];
    while(i < j)
    {
        while(i<j && R[j].key >= pivot.key)
            j--;
        if (i < j)
            R[i++] = R[j];
        while(i<j && R[i].key <= pivot.key)
            i ++;
        if(i<j)
            R[j--] = R[i];
    }
    R[i] = pivot;
    return i;
}
冒泡排序

扫描n-1次,每次扫描让无序区中的最“轻”气泡上升到“顶部”
若原始数据是正序的,则比较次数为n-1,移动次数为0,时间复杂度为O(n);若原始为反序,则比较次数和移动次数都达到O(n^2)
算法的平均时间复杂度为O(n^2)
冒泡排序为就地排序,是稳定的。但性能要比快速排序要差很多。

void BubbleSort(SeqList R)
{
    int i, j;
    Boolean exchange;
    for(i=1;i<n;i++) // 1,..., n是待排序的数
    {
        exchange = FALSE;
        for(j=n-1;j>=i;j--)
        {
            if(R[j+1].key < R[j].key)
            {
                R[0] = R[j+1];
                R[j+1] = R[j];
                R[j] = R[0];
                exchange = TRUE;
            }
        }
        if(!exchange)
            return ;
    }
}
shell排序(希尔排序)

插入排序的一种,本质是一种分组插入的方法
当增量为1时,与insertSort基本一致,只是由于没有哨兵而在内循环中增加了一个循环判定条件j>0以防止下标越界
执行时间依赖于增量序列,最后一个增量必须为1,应尽量避免序列中的中(尤其是相邻的值)互为倍数的情况

性能优于直接插入排序,原因如下:

  • 当文件初态基本有序时,直接插入排序所需的比较和移动次数都比较少
  • 当n较小时,n与n^2差别也比较小,即直接插入排序的最好时间复杂度和最坏复杂度差别不大
  • 希尔排序开始增量较大,分组多,每组记录少,故各组直接插入排序较快。增量逐渐减少,各组数量虽然增多,但接近有序,所有新的一趟排序也较快
  • 希尔排序是不稳定的。
void ShellPass(SeqList R, int d)
{
    for(i=d+1; i<=n;i++)
    {
        if (R[i].key < R[i-d].key){
            R[0] = R[i];
            j = i-d;
            do {
                R[j+d] = R[j];
                j = j-d;
            }while(j>0 && R[0].key<R[j].key);
            R[j+d] = R[0];
        }
    }
}
void ShellSort(SeqList R)
{
    int increment = n; //增量初值
    do {
        ShellPass(R, increment);
        increment = increment / 3 + 1;
    }while (increment > 1)
}

总结

稳定排序 时间复杂度 空间复杂度
冒泡排序 最差、平均都是O(n^2);最好是O(n) 1
鸡尾酒排序 最差、平均都是O(n^2);最好是O(n) 1
插入排序 最差、平均都是O(n^2);最好是O(n) 1
归并排序 最差、平均、最好都是O(nlogn) O(n)
桶排序 O(n) O(k)
基数排序 O(dn) d是常数 O(n)
二叉树排序 O(nlogn) O(n)
图书馆排序 O(nlog(n) (1+ξ)n
不稳定的排序 时间复杂度 空间复杂度
选择排序 最差、平均都是O(n^2) 1
希尔排序 O(nlogn) 1
堆排序 最差、平均、最好都是O(nlogn) 1
快速排序 平均是O(nlogn) ;最坏都是O(n^2) O(n)

不同条件下排序方法的选择

  1. n较小 (如n<50), 可采用直接插入或者直接选择排序

当规模小时,直接插入排序较好;否则,因为直接选择移动的记录数少于直接插入,应该直接选择排序为宜。

  1. 若文件初始状态基本有序(指正序),则应该选用直接插入排序、冒泡排序或者随机的快速排序为宜
  2. 若n较大,应采用时间复杂度为O(nlogn)的排序方法(快排、堆排序、归并排序)

快速排序是目前基于比较的内部排序中最好的方法。当待排序的关键字随机分布时,快速排序的平均时间最短

  1. 堆排序所需要的辅助空间少于快速排序,并且不会出现快速排序可能出现的最坏情况,但和快排都是不稳定的
  2. 若要求排序稳定,则可选归并排序。但不提倡从单个记录起进行两两归并,通常和直接插入排序合在一起用,先利用直接插入法求得较长的有序子文件,然后再两两归并。

6. 以下哪种结构,平均来讲获取任意一个指定值最快,为什么?

  • [ ] A. 二叉排序树
  • [x] B. 哈希表
  • [ ] C. 栈
  • [ ] D. 队列

7. 辗转相除法的时间复杂度是多少?

解析:算法的思想:gcd(a, b) = gcd(b, a mod b),时间复杂度是O(logn)

8.字符串

8.1 怎么将整数转化为字符串数,并且不用函数itoa?

解析:整数转化为字符串,可以采用加’0’,再逆序的办法,整数加’0’就会隐形转化成char类型的数。

8.2 怎么将字符串转化成整数?

解析:字符串转化为整数,可以采用’0’再乘10累加的方法,字符串减’0’就会隐形转化成int类型的数

8.3 不使用C++/C的字符串库函数,编写函数strcpy
char *strcpy(chr *strDest, const char *strSrc)
{
    assert ((strDest != NULL) && (strSrc != NULL));
    char *address = strDest;
    while( (*strDest++ = *strSrc) != '\0' )
    NULL;
    return address;
}
8.4 strcpy能把strSrc的内容复制到strDest,为什么还要char *类型的返回值?

解析:为了实现链式表达式,返回具体的值int length=strlen(strcpy(strDest, “hello world”))

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容