2015校招笔试面试算法总结之蓝汛笔试

一、递增矩阵问题

问题描述:如下图所示,在一个m*n矩阵中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,按从小到大的顺序打印这个矩阵到一个一维数组中。如图,则应打印出1,2,2,4,4,6,7,8,8,9,9,10,11,12,13,15.

二、无重复的最长子串问题(引用luxiaoxun博客)

问题描述:找到一个字符串中的一个连续子串,这个子串内不能有任何两个字符是相同的,并且这个子串是符合要求的最长的。例如输入"abcbef",输出"cbef"。

问题求解:方法一:穷举法,使用2重外循环遍历所有的区间,用2重内循环检验子串是否符合“无重复字符”这一要求。其中外层循环i、j 遍历所有的下标,m、n是内层循环,检查区间[i,j]是否符合要求。空间复杂度是O(1),时间复杂度O(N^4)。

//O(N^4)的时间复杂度
int max_unique_substring1(char * str)
{
    int maxlen = 0;
    int begin = 0;
    int n = strlen(str);
    for(int i=0; i<n; ++i)
        for(int j=1; j<n; ++j)
        {
            int flag = 0;
            for(int m=i; m<=j; ++m)
            {
                for(int n=m+1; n<j; ++n)
                {
                    if(str[n] == str[m])
                    {
                        flag = 1;
                        break;
                    }
                }
                if(flag == 1) break;
            }
            if(flag==0 && j-i+1>maxlen)
            {
                maxlen = j-i+1;
                begin = i;
            }
        }
    printf("%.*s\n", maxlen, &str[begin]);
    return maxlen;
}  

方法二:对方法一的检验子串是否“无重复字符”进行改进,使用hash表记录字符是否出现过。

//O(N^2)的时间复杂度
int max_unique_substring2(char * str)
{
    int i,j;
    int begin;
    int maxlen = 0;
    int hash[256];
    int n = strlen(str);
    for(i=0; i<n; ++i)
    {
        memset(hash,0,sizeof(hash));
        hash[str[i]] = 1;
        for(j=i+1; j<n; ++j)
        {
            if(hash[str[j]] == 0)
                hash[str[j]] = 1;
            else
                break;
        }
        if(j-i > maxlen)
        {
            maxlen = j-i;
            begin = i;
        }
    }
    printf("%.*s\n", maxlen, &str[begin]);
    return maxlen;
}  

方法三:对于字符串"axbdebpqawuva",构造下表:

表中,字符串有3个‘a’,有2个‘b’,其余为单一字符。next[]记录了下一个与之重复的字符的位置,如str[0]=str[8]=str[12]=‘a’,这时next[0]=8,next[8]=12,next[12]=13,其余同理。值得注意的是,对于没有重复字符的,next[]存储字符结束符‘\0’的下标,即13。

这里,first[i]表示i之后,第一次出现重复字符的那个位置。例如,str[0]之后,第一次出现的重复字符是str[5]=‘b’,当然,从str[1],str[2]开始也是一样。而从str[3]开始,要到str[12]才出现重复字符‘a’。可以证明,从str[i]起的最长符合要求的长度为first[i]-i,区间为[i,first[i]-1]由此得解。上述最长串是当i=3时,first[i]-i=12-3=9。结果串为debpqawuv。

//O(N)的时间复杂度
int max_unique_substring3(char * str)
{
    int maxlen = 0;
    int begin = 0;
    int n = strlen(str);
    int * next = (int*)malloc(sizeof(int)*n); //next[i]记录了下一个与str[i]重复的字符的位置
    int * first = (int*)malloc(sizeof(int)*(n+1)); //first[i]记录str[i]后面最近的一个重复点
    int hash[256];
    memset(hash,n,sizeof(hash));  

    first[n] = n;
    for(int i=n-1; i>=0; i--)
    {
        next[i] = hash[str[i]];
        hash[str[i]] = i;
        if (next[i] < first[i+1])
            first[i] = next[i];
        else
            first[i] = first[i+1]; //生成first[]表,复杂度是O(N)的
    }
    for(int i=0; i<n; i++)
    {
        if (first[i]-i > maxlen)
        {
            maxlen = first[i]-i;
            begin = i;
        }
    }
    free(first);
    free(next);
    printf("%.*s\n", maxlen, &str[begin]);
    return maxlen;
}  

方法四:使用后缀数组

对这个字符串构造后缀数组,在每个后缀数组中,寻找没有重复字符的最长前缀,最长的前缀就是要找的子串

//得到字符串最长的无重复的前缀长度
int longestlen(char * p)
{
    int hash[256];
    int len = 0;
    memset(hash,0,sizeof(hash));
    while (*p && !hash[*p])
    {
        hash[*p] = 1;
        ++ len;
        ++ p;
    }
    return len;
}  

//使用后缀数组解法
int max_unique_substring4(char * str)
{
    int maxlen = -1;
    int begin = 0;
    char *a[99999];
    int n = 0;
    while(*str != '\0')
    {
        a[n++] = str++;
    }
    for (int i=0; i<n; i++)
    {
        int temlen = longestlen(a[i]);
        if (temlen > maxlen)
        {
            maxlen = temlen;
            begin = i;
        }
    }
    printf("%.*s\n", maxlen, a[begin]);
    return maxlen;
}  

方法五:DP方案等参考http://www.ahathinking.com/archives/123.html

三、字符串交错问题

问题描述:判断字符串c是否是字符串a和字符串b按顺序的交错(interleave)。

什么叫interleave?是将两个字符串完整的交错在一起,拆分开以后还会是原来的a和b串。

问题分析:一个直观的错觉:把C字符串中的A挑出来,剩下的部分如果是B,这样就说明C是interleave。

这样会遇到一个错误,比如a="aa", b="ab", c="aaba"。如果从c中把A挑出来,会直接挑出开始的"aa",然后剩余的部分"ba"不等于b字符串,就会做出“不是interleave”的错误判断。这样的错误是由于a、b两个字符串中有共有的字符所导致的挑拣时的错误。

情况一:如果输入字符串a、b中没有共有的字符,那么各挑各的,挑到就一定是属于自己的。如果挑完之后c还有剩余、或者挑不完c就没了,说明c不是interleave。

情况二:如果输入字符串a、b中是有共有字符的,那么各挑各的,很有可能发生挑选错误,把不该挑走的挑走。想要避免这个错误,当遇到共有字符时(即,两方都能要的字符),分别把两种情况都考虑。

下面是解决问题的两种方向。

1、递归方法:由外向里(由大向小)解决问题。

2、DP方法:由里向外(由小向大)解决问题。

递归子问题方法:

对于目标问题(s1, s2, s3)来说,递归子问题是(s1.substr(1), s2, s3.substr(1))和(s1, s2.substr(1), s3.substr(1))两个。

class Solution {
public:
    bool isInterleave(string s1, string s2, string s3) {
        bool r1 = false, r2 = false;  

        if(s1 == "" && s2 == "" && s3 == "")
            return true;
        if(s1 != "" && s3 != "" && s1[0] == s3[0])
            r1 = isInterleave(s1.substr(1), s2, s3.substr(1));
        if(s2 != "" && s3 != "" && s2[0] == s3[0])
            r2 = isInterleave(s1, s2.substr(1), s3.substr(1));
        return r1 || r2;
    }
};  

动态规划方法:

国际惯例,首先找子问题,设计子问题状态量。

对于目标问题(s1, s2, s3)来说,子问题是(s1的前i个字符,s2的前j个字符,s3的前i+j个字符)。

设子问题状态量C[i][j],其表示,问题(s1的前i个字符,s2的前j个字符,s3的前i+j个字符)的状态(true或false)。那么C[s1.length()][s2.length()]就是目标问题的状态。

初始问题状态C[0][0]=true。

状态递推关系为: C[i][j] = ( (s1[i-1] == s3[i+j-1]) && C[i-1][j] ) || ( (s2[j-1] == s3[i+j-1]) && C[i][j-1] )

代码:

class Solution {
public:
bool isInterleave(string s1, string s2, string s3) {
    size_t len1, len2;
    len1 = s1.length();
    len2 = s2.length();
    if(len1 + len2 != s3.length())
        return false;  

    bool **C = new bool*[len1+1]; //注意*在中间
    for(int i=0;i<len1+1;i++)
        C[i] = new bool[len2+1];  

    C[0][0] = true;
    for(int i=1;i<len1+1;i++)
        C[i][0] = (s1[i-1] == s3[i-1]) && C[i-1][0];  

    for(int j=1;j<len2+1;j++)
        C[0][j] = (s2[j-1] == s3[j-1]) && C[0][j-1];  

    for(int i=1;i<len1+1;i++)
        for(int j=1;j<len2+1;j++)
            C[i][j] = ( (s1[i-1] == s3[i+j-1]) && C[i-1][j] ) || ( (s2[j-1] == s3[i+j-1]) && C[i][j-1] );  

    bool result = C[len1][len2];  

    for(int i=0;i<len1+1;i++)
        delete []C[i];
    delete []C;
    return result;
}  

};  

DP方法的时间复杂度O(mn),空间复杂度O(mn)。

四、统计某时间段内在线用户数问题

问题描述:统计指定时间段内每个时间点有多少个用户.时间段是开始时间 00:00 结束时间 08:00

比如一个用户 A 的记录表示为User:login_time:logout_time

表中示例数据

User            login_time       logout_time

A                    05:57           09:01

B                     07:13           08:00

C                     05:00          07:00

最后记录为[5,7),2  [7,8),2 [8,9),1 而不是[5,6),2  [6,7),2  [7,8),2 [8,9),1

(未完待续)

时间: 2024-12-10 13:00:25

2015校招笔试面试算法总结之蓝汛笔试的相关文章

Java 笔试面试 算法编程篇 一

方法 1 /* ********************************************************************************** 1.编写一个程序,将a.txt文件中的单词与b.txt文件中的单词交替合并到c.txt文件中, a.txt文件中的单词用回车符分隔,b.txt文件中用回车或空格进行分隔. *************************************************************************

12种排序算法:原理、图解、动画视频演示、代码以及笔试面试题目中的应用

出处:http://blog.csdn.net/han_xiaoyang/article/details/12163251. 声明:版权所有,转载请注明出处,谢谢. 0.前言 从这一部分开始直接切入我们计算机互联网笔试面试中的重头戏算法了,初始的想法是找一条主线,比如数据结构或者解题思路方法,将博主见过做过整理过的算法题逐个分析一遍(博主当年自己学算法就是用这种比较笨的刷题学的,囧),不过又想了想,算法这东西,博主自己学的过程中一直深感,基础还是非常重要的,很多难题是基础类数据结构和题目的思想综

算法之美一书附录中笔试面试题目参考答案

探秘算法世界,求索数据结构之道:汇集经典问题,畅享编程技法之趣:点拨求职热点,敲开业界名企之门.<算法之美--隐匿在数据结构背后的原理>全文目录."45个算法"目录."22个经典问题目录",请见如下链接: 算法之美隆重上市欢迎关注(更有三重好礼) http://blog.csdn.net/baimafujinji/article/details/50484348 *本书附录中的笔试面试题目主要从我之前的系列博文<常见C++笔试题目整理(含答案)&g

C++笔试面试(算法题集三)

1>    编写strcpy函数,已知函数原型char*strcpy(char* strDest,char* strSrc) ANSWER: Chat* strcpy(char* strDest,char* strSrc) { If(strSrc==NULL)  return NULL; Char*ch1=strSrc,*ch2=strDest; While(*ch1!='\0') { *ch2++=*ch1++; } *ch2='\0'; Return strDest; } 2>    用递

leetcode 刷500道题,笔试/面试稳过吗?谈一谈这些年来算法的学习

想要学习算法.应付笔试或者应付面试手撕算法题,相信大部分人都会去刷 Leetcode,有读者问?如果我在 leetcode 坚持刷它个 500 道题,以后笔试/面试稳吗? 这里我说下我的个人看法,我认为不稳.下面说说为啥不稳以及算法题应该如何刷.如何学才比较好,当然,也会推荐自己学过的资料. 一.先说说笔试题 在刷 leetcode 的时候,你会发现,每道题的题意都很短,你只需要花十几秒的时间,就知道这道题是要你干嘛了,并且每道题所用道的算法思想都很明确,动态规划.递归.二分查找等,你可能很快就

阿里巴巴暑期实习面试-算法岗位(机器学习)2018-03-28

一面是电面,包括电话交流与在线编程,持续时间72分钟,知识点以及涉及到的知识点如下: 在零星地说一些其他的感悟: 1.面试的过程其实也是一个学习的过程,这次面我的这个面试官人很好,虽然我热别菜,但是他还是很耐心,在一步步引导我,最后和他交流学习方法我也受益匪浅.所以每次笔试面试,都一定要进行总结,不能在同样的石头上摔两次.还有就是平时一定能多学就多学,比如有一次笔试回来,才发现我不会的那个题目恰好是<剑指offer>最后一道题,我还没来得及看 2.校招和实习更看重基础和态度,我问面试官&quo

《Python程序员面试算法宝典》PDF高清版

<Python程序员面试算法宝典>PDF高清版 链接: https://pan.baidu.com/s/1Rtvk_KCmdwvGliyq9Pg9OQ 提取码: i69a ? 内容简介  · · · · · · 本书是一本讲解程序员面试笔试算法的书,代码采用Python语言编写,书中除了讲解如何解答算法问题以外,还引入了例子辅以说明,让读者更容易理解. 本书几乎将程序员面试笔试过程中算法类真题一网打尽,在题目的广度上,通过各种渠道,搜集了近3年来几乎所有IT企业面试笔试算法的高频题目,所选择题

php 笔试面试 总结

一次小小的笔试面试经历,虽然是一些简单的问题,但是自己在这儿总结一下,也查一些资料,得出一些较好的答案,也能帮助自己成长. 1.自己熟悉的http状态码及其意义 其实这个题答案随处可见.这儿也还是记录一下我们常见的http状态码 200:请求返回的状态正常. 301:url永久性重定向. 302:url暂时性重定向. 400:错误请求. 401:未授权访问. 403:禁止访问. 404:未找到 500:服务器错误. 502:bad gateway.错误网关. 504:Gateway Timeou

面试算法

July 西电讲座 2014.09 第一部分.面试 –笔试面试考什么 –解决笔试面试题的常用算法 –常用算法的时间复杂度 –O(N)时间复杂度内能解决的问题 第二部分.算法 –如何学习算法 循序渐进(KMP) 相互串联(以Trie树.后缀树,贪心.动态规划为例) 追本溯源(二叉树.红黑树.2-3-4树.B树为例) –海量数据处理面试题 十种解决之道 第三部分.机器学习 –SVM的简单介绍,与SMO的简单推导 数据结构上的增删改查(查找.遍历.排序) [字符串 –字符串库函数的编写,例如atoi