百度实习生面试(2013年12月2号)

        

        前一段时间面过百度商务搜索部门的软件开发实习生,面了3面,没有通过,还差的很远。百度对算法的要求还是比较高的,虽然时间过去了一段时间了,但是有些题目还是可以记起来。特此发篇博客,记录下内容,也以此激励自己,希望下次在去会有进步。


        整个面试过程大概写了7 8 道程序题目把,脑袋都写大了。通过这次面试知道了有两个需要注意和锻炼的地方:


        1.在纸上写代码的能力。最好带支铅笔和橡皮过去,如果你字写的不好看,写的时候在涂涂画画修改下,会显得代码乱七八糟的,自己看着都觉得恶心。更别提面试官了。如果没有绝对的实力一遍写过,最好用铅笔和橡皮,错了还可以擦掉。


        2.在写代码的时候一定要特别注意某些边界条件的判断,尤其要小心。虽说不是什么大错误,但是被面试官发现的话是相当不好的。囧,自己发现了2处。譬如说我在写的时候犯的错误,双链表的最后一个节点的判断条件不是等于空,而是指向第一个头节点。


        好了,没有面过就继续努力,吸取下经验教训。继续往前走。下面记录下遇到的程序题目。


        一面:

        

        非代码题目:


        除了写代码之外问的都比较基础,譬如 虚函数  static关键字的作用, const 关键字的作用。(这里需要注意const的位置不同,代表的含义不同)。

       代码题目:

       

       1.数组中有一个出现次数超过数组一半的数字,请找出来这个数字


        这个题目算是比较常见的了, 在剑指offer上也出现过了,也给出了2种解法。
  
        解法1:基于partition函数的解法

        数组中的一个数字出现的次数超过数组的一半,那么排序后这个数组的中间的数字一定是这个出现了一半次数的数字。也就是数组的中位数。我们可以把问题简化到求数组  第 n/2大的数字。

        算法是受到快速排序算法的启发,在数组中随机选中一个数字,然后调整数组的顺序,使得比选中数组小的数字都在数字的左边,比选中的数字大的数字都在数字的右边。这个就是partition算法。如果这个选中的数字下标刚好是n/2,那么可以返回了,如果大于n/2,则中位数在他的左边,我们可以在左边的数组中查找。

        
#include <iostream>

using namespace std;
void Swap( int & x, int & y ){
    int temp = x;
    x = y;
    y = temp;
}
int partition ( int a[ ], int begin ,int  end ){
    int temp = a[ begin ];
    int i,j;
    i = begin;
    j = end;
    while( i < j ){
        while( a[ j ] >= temp && i < j )
            j --;
        if( i < j ){
            Swap( a[j], a[ i ] );
            i++;
        }
        while( a[ i ]  <= temp && i < j )
            i++;
        if( i < j ){
            Swap( a[ j ], a[ i ] );
            j --;
        }
    }
    a[ i ] = temp;                                                                                                                                              return i;
}
bool isInputInValid = false;
bool CheckInvalidArray( int numbers[ ], int length ){
    isInputInValid = false;//初始认为输入正确
    if( NULL == numbers || length <= 0 ){
        isInputInValid = true;
    }
    return isInputInValid;
}
bool CheckMoreThanHalf( int numbers[ ], int length, int result  ){
    int nums = 0;
    for( int i = 0; i < length; i ++ ){
        if( numbers[ i ] == result )
            nums++;
    }
    bool isMoreThanHalf = true;
    if( nums * 2 <= length ){
        isInputInValid = true;
        isMoreThanHalf = false;
    }
    return isMoreThanHalf;
}
int MoreThanHalfNum( int numbers[ ], int length ){
    //面试的时候一定要处理参数的输入是否正确
    if( CheckInvalidArray( numbers, length ) )
        return 0;
    int middle = length >> 1;
    int start = 0;
    int end = length - 1;
    int partitionIndex = partition( numbers, start, end );
    while( partitionIndex != middle ){
        if( partitionIndex > middle ){
            end = partitionIndex - 1;
            partitionIndex = partition( numbers, start, end );
        }
        else{
            start = partitionIndex + 1;
            partitionIndex = partition( numbers, start, end );
        }
    }
    int result =  numbers[ middle ];
    if( !CheckMoreThanHalf( numbers, length, result ) )
        result = 0;
    return result;
}
int main()
{
    int num[ ] = {1,2,3,2,2,2,5,4,2};
    int result = MoreThanHalfNum( num, 9 );
    if( isInputInValid == true  ){
        if( result == 0)
            cout << "Input Error,the Arry does not has not half element " << endl;
        else
            cout << "Input Error " << endl;
    }
    else
        cout << result << endl;


    return 0;
}
            在面试的时候,一定要处理参数的输入是否正确。譬如说本题目,需要考虑2点
        1.传入的数组退化成指针的时候是否为空,或者length 是否小于等于0
        2.找到了中间的值,但是有可能这个值没有在数组中出现一半以上。这也是需要考虑的的一点。


         方法2:另外一种方法,方法1主要消耗在排序上面,如果我们能跳过排序这个步骤,只扫描一遍数组就能找到的话就太好了。我在面试的时候做出来第一种方法后 被特别要求用另外一种方法来做。

         对于数组,我们假设每次删除2个不同元素的值,则剩余的数组中,原先出现频率大于一半的还是会大于一半。一直重复删除,直到剩下的全是同样的数字。则必定是出现了一半次数的那个值。时间复杂度为o(n)

        代码:
#include <iostream>

using namespace std;

bool isInputInValid = false;
bool CheckInvalidArray( int numbers[ ], int length ){
    isInputInValid = false;//初始认为输入正确
    if( NULL == numbers || length <= 0 ){
        isInputInValid = true;
    }
    return isInputInValid;
}
bool CheckMoreThanHalf( int numbers[ ], int length, int result  ){
    int nums = 0;
    for( int i = 0; i < length; i ++ ){
        if( numbers[ i ] == result )
            nums++;
    }
    bool isMoreThanHalf = true;
    if( nums * 2 <= length ){
        isInputInValid = true;
        isMoreThanHalf = false;
    }
    return isMoreThanHalf;
}
int MoreThanHalfNum( int numbers[ ], int length ){
    //面试的时候一定要处理参数的输入是否正确
    if( CheckInvalidArray( numbers, length ) )
        return 0;
    int count = 1;
    int result = numbers[ 0 ];
    for( int i = 1; i < length; i++ ){
        if( 0 == count ){
            result = numbers[ i ];
            count = 1;
        }
        if( numbers[ i ] == result ){
            count++;
        }
        else
            count--;
    }
    if( !CheckMoreThanHalf( numbers, length, result ) )
        result = 0;
    return result;
}
int main()
{
    int num[ ] = {1,0,3,2,2,2,5,4,2};
    int result = MoreThanHalfNum( num, 9 );
    if( isInputInValid == true  ){
        if( result == 0)
            cout << "Input Error,the Arry does not has not half element " << endl;
        else
            cout << "Input Error " << endl;
    }
    else
        cout << result << endl;


    return 0;

}

        题目2:双链表的删除操作


        这个没什么要写的,唯一要注意的是判断是否链表最后一个节点的判断条件是next指针指向头节点,而不是判断为空。


        二面:


        二面的面试官很和蔼,而且年纪看起来很小。应该也是刚毕业那种。随便自我介绍了下,就开始做题了。

        题目1:如何求出来一个数组的连续最大和


        这个题目也算是常见题目了,在各大公司面试中出现频率特别频繁。

        思路:
        
        1.当我们加上一个正数时,和会增加;当我们加上一个负数时,和会减少。如果当前得到的和是个负数,那么这个和在接下来的累加中应该抛弃并重新清零,不然的话这个负数将会减少接下来的和。 设置置两个变量 ,初始值都为0,一个记录最大连续和result,一个记录连续和sum,对于数组中的每个值,我们有两种选择,对于正的数值,sum相加,如果大于result,则更新result。对于负数值A[i],我们要考虑两种情况:1) 如果sum+A[i] <= 0,则前面的连续和则失去了意义,将sum重新置为0,如果sum+A[i]大于0,则相加,看后续情况。
int LongConsequiveNum( int A[], int length ){
    int sum = 0, result = 0;
    for( int i = 0; i < length; i++ ){
        if( A[ i ] > 0 ){
            sum += A[ i ];
            if( sum > result )
                result = sum;
        }
        else{
            if( A[ i ] + sum <= 0 ){
                sum = 0;
            }
            else{
                sum += A[ i ];
            }
        }
    }
    return result ;
}


         july博客上有仔细的讲解,传送门:http://blog.csdn.net/v_JULY_v/article/details/6444021

int MaxSubsequenceSum(const int A[],int N)  
{  
    int ThisSum,MaxSum,j;  
    ThisSum=MaxSum=0;  
    for(j=0;j<N;j++)  
    {  
        ThisSum+=A[j];  
        if(ThisSum>MaxSum)  
            MaxSum=ThisSum;  
        else if(ThisSum<0)  
            ThisSum=0;  
    }  
    return MaxSum;  
} 


        另外这个求数组连续最大和也可以用动态规划来做:
        
        将子问题设MaxLen[i]表示以A[i]结尾 的子数组的最大子段和,即: MaxLen[i]=max{MaxLen(i - 1) ,0} + A[i],状态转移方程写出来了,其余代码就简单了。

//
//  MaxSum.cpp
//  MaxSum
//
//  Created by chenhao on 12/17/13.
//  Copyright (c) 2013 mini. All rights reserved.
//

#include <iostream>
using namespace std;
#define INTMIN -1000
const int MAX_SIZE =  100;

int data[ MAX_SIZE + 10 ];
int MaxLen[ MAX_SIZE + 10 ];
int N;
int main(int argc, const char * argv[])
{
    while( cin >> N ){
        for( int i = 1; i <= N; i++ )
            cin >> data[ i ];
        MaxLen[ 1 ] = data[1];
        for( int i = 2; i <= N; i++ ){
            if ( MaxLen[ i - 1 ] + data[ i ] > data[ i ] )
                MaxLen[ i ] = MaxLen[ i - 1 ] + data[ i ];
            else
                MaxLen[ i ] = data[ i ];
        }
        int result = INTMIN;
        for( int i = 1; i <= N; i++ )
            if( result < MaxLen[ i ] )
                result = MaxLen[ i ];
        cout << result << endl;

    }
}



        题目2:求出来题目1后,立马让求二维数组,二维的没写出来。悲剧。





        
        

你可能感兴趣的:(算法,面试,百度,软件开发)