百度武汉站

来源:互联网 发布:程序员被骗婚 编辑:程序博客网 时间:2024/04/29 20:41

百度2014校招笔试题目题解

----武汉站,9.28号百度校招笔试题目算法题目部分

二、算法与程序设计题

1、给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数”的含义是相邻两位不相同,例如1101是重复数,而1201是不重复数。(15分)

2、长度为N(N很大)的字符串,求这个字符串里的最长回文子串。(15分)

3、数轴上从左到右有n各点a[0], a[1], ……,a[n -1],给定一根长度为L的绳子,求绳子最多能覆盖其中的几个点。(15分)

这是百度的笔试题目,好像是什么系统行为分析师职位的笔试题目!博文最后会贴出试题照片!

题解:(题解非官方,仅供参考,转载请联系博主,有错误的地方望指正!谢谢)

1、给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数”的含义是相邻两位不相同,例如1101是重复数,而1201是不重复数。

解: 这道题目我也没有什么特别出彩的算法,就是按照常规思路来求解,首先要理解什么叫做“不重复数”,这是解题的关键之一,相邻两位不相同的数即为“不重复数”;还有一个地方要注意的就是“求比这个数大且最小的”,就是在比给定数大的不重复数中找到最小的!理解了这两个地方,这道题目就可以着手求解了!

  我用一个实例来说说我的思路,假如给定的正整数为11233:

  用最常规的方法,就是每次对这个数加1,判断是不是“不重复数”,加1后为11234,有两个1重复了,于是继续加1,……,那么主要就在判断是不是“不重复数”上面了,我设置了两个变量,是currentBit, lastBit,顾名思义,lastBit保存上一个数位的值,currentBit保存当前数位的值,拿整数12345来说,就是初始化lastBit = 5,然后计算currentBit = 4;下一步,把currentBit 值赋给lastBit,即lastBit = 4,计算currentBit = 3;依次类推。

  说到这里,很多朋友觉得可以有更加高效的方法,小难点有4:

  1、因为可以直接定位到“重复”的数位的位置,比如12344,我们可以直接定位到个位数4和十位数4上面,然后在低数(这里就是个位数)上加1即可,事实上,不是如此简单,假设是对整数12199呢?还能简单的加1操作吗,加1之后结果为12200,那结果显然是错的,当然这也是可以处理的,处理方法就是把12200继续拿到循环去处理,再判断是不是“不重复数”;

  2、这里又产生一个问题,因为“重复“的数位可能不止一对,有可能有多对,比如整数11233,定位“33”之后变为“34”,定位“11”之后变为“12”,结果就是12234。又有重复的地方,就是“22”。继续拿到循环去重复;

  3、还有要注意的是,你的程序的设计,是如何存储数位的值的,是一个一个数位的值求出来呢?还是像我这样设置一个前后索引?把每个数位的值求出来并且存储,程序会变得繁琐复杂,不易读懂,如果是设置前后索引,则要注意程序退出循环的条件!

  4、对于存在多对“重复”数位的正整数,数位“重复”的定位和变换,是从高位到低位,还是从低位到高位呢?正确的应该是从高位到低位,这给我们的程序设计也带来了不便。

  这些就是我在试图找到高效算法时得到的经验,每个小难点都要处理,有点繁琐,有耐心的朋友,可以试着写一下更高效的算法,另外,使用了比较高效的算法,代码尽量保持简洁,并告知博主,谢谢!

  my code:(简单加1的方法)

[cpp] view plaincopyprint?
  1. /*
  2. 给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数的含义是相邻两位不相同,例如1101是不重复数”
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. int getNumNonrepetition(constint NumGived)
  7. {
  8. int flag = 0;//为0表示该数不是“不重复数”
  9. int numRepeat = NumGived;
  10. int numTemp = 0;//
  11. int currentBit = 0, lastBit = 0;//前后数位索引
  12. while(1)
  13. {
  14. numRepeat++;
  15. //初始化后索引
  16. numTemp = numRepeat;
  17. lastBit = numTemp % 10;
  18. numTemp /= 10;
  19. flag = 1;
  20. //判断该数是不是“非重复数”
  21. while(numTemp != 0)
  22. {
  23. currentBit = numTemp % 10;
  24. numTemp /= 10;
  25. if(lastBit == currentBit)
  26. {
  27. flag = 0;
  28. break;
  29. }
  30. lastBit = currentBit;
  31. }
  32. if(flag == 1)//该数为不重复数,返回
  33. {
  34. return numRepeat;
  35. }
  36. }
  37. }
  38. int main(void)
  39. {
  40. int NumGived = 19922884;
  41. int result = getNumNonrepetition(NumGived);
  42. printf("the number is %d\n", result);
  43. return 0;
  44. }
/*    给定任意一个正整数,求比这个数大且最小的“不重复数”,“不重复数的含义是相邻两位不相同,例如1101是不重复数”*/#include <stdio.h>#include <stdlib.h>int getNumNonrepetition(const int NumGived){    int flag = 0;//为0表示该数不是“不重复数”    int numRepeat = NumGived;    int numTemp = 0;//    int currentBit = 0, lastBit = 0;//前后数位索引    while(1)    {        numRepeat++;        //初始化后索引        numTemp = numRepeat;        lastBit = numTemp % 10;        numTemp /= 10;        flag = 1;        //判断该数是不是“非重复数”        while(numTemp != 0)        {            currentBit = numTemp % 10;            numTemp /= 10;            if(lastBit == currentBit)            {                flag = 0;                break;            }            lastBit = currentBit;        }        if(flag == 1)//该数为不重复数,返回        {            return numRepeat;        }    }}int main(void){    int NumGived = 19922884;    int result = getNumNonrepetition(NumGived);    printf("the number is %d\n", result);    return 0;}


2、长度为N(N很大)的字符串,求这个字符串里的最长回文子串。

解:题目指出“N很大”,就是提示我们不要想通过遍历的方法来找到这个字符串,我想到的就一种解法,时间复杂度应该不高,但是我算不出来这个算法的复杂度是多少,首先说一下什么是回文字符串:回文字符串是指从左到右和从右到左相同的字符串,比如"1221"或者“12321”都是回文字符串。刚好举得这两个回文字符串的例子就是我的算法的两个类别:

  第一类“12321”:中间是一个单独的字符。算法的思想是从第2个字符直到倒数第2个字符遍历,每遇到一个字符,就依次判断这个字符前后的字符是否相等,如果相等,则继续判断下一个字符,直到以这个字符为中心的两边对称的字符不相等为止,或者前后字符的位置数组越界为止;计算此时的回文字符串的长度,与之前的比较,记下较长的回文字符串的长度和中心字符的位置;遍历结束则返回最大长度和中心字符的位置

  图示:若字符串为“1234321”

  第二类“123321”:中间是两个相同的字符。算法思想同上,其实是一样的过程!图解也是一样的!

my code:

[cpp] view plaincopyprint?
  1. /*
  2. 长度为N(N很大)的字符串,求这个字符串里的最长回文子串。
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. //第一类“12321”:中间是一个单独的字符
  8. int FindLongPaliSubstr_Odd(constchar A[], int * indexMid)
  9. {
  10. int i = 0, cnt = 0;//cnt表示前后移动位数
  11. int MyMax = 0;
  12. int lenOfA = strlen(A);
  13. *indexMid = 0;
  14. for(i = 1; i <= lenOfA - 2; i++)
  15. {
  16. cnt = 0;
  17. while(i - cnt >= 0 && i + cnt <= lenOfA - 1 && A[i - cnt] == A[i + cnt])
  18. {
  19. cnt++;
  20. }
  21. cnt--;
  22. //找到较大长度的回文字符串,保存中心字符的位置
  23. if(MyMax < 2 * cnt + 1)
  24. {
  25. MyMax = 2 * cnt + 1;
  26. *indexMid = i;
  27. }
  28. }
  29. return MyMax;
  30. }
  31. //第二类“12321”:中间是两个相同的字符。
  32. int FindLongPaliSubstr_Even(constchar A[],int * First)
  33. {
  34. int i = 0, cnt = 0;//cnt表示前后移动位数
  35. int MyMax = 0;
  36. int lenOfA = strlen(A);
  37. *First = 0;//中间两个相同字符的第一个字符位置
  38. for(i = 0; i <= lenOfA - 2; i++)
  39. {
  40. if(A[i] == A[i + 1])
  41. {
  42. cnt = 1;
  43. while(i - cnt >= 0 && (i + 1 + cnt) <= lenOfA - 1 && A[i - cnt] == A[i + 1 + cnt])
  44. {
  45. cnt++;
  46. }
  47. cnt--;
  48. //找到较大长度的回文字符串,保存中心第一个字符的位置
  49. if(MyMax < 2 * cnt + 2)
  50. {
  51. MyMax = 2 * cnt + 2;
  52. *First = i;
  53. }
  54. }
  55. }
  56. return MyMax;
  57. }
  58. int main(void)
  59. {
  60. char A[] = "adfadfbadfdg12321fagage";
  61. int indexMid = 0;
  62. int First = 0;
  63. int i = 0;
  64. //两种类别的最长回文子串的长度
  65. int MaxOdd = FindLongPaliSubstr_Odd(A, &indexMid);
  66. int MaxEven = FindLongPaliSubstr_Even(A, &First);
  67. printf("indexMid = %d\n", indexMid);
  68. printf("First = %d\n", First);
  69. //哪类比较大,输出哪一类的回文子串
  70. if( MaxOdd > MaxEven)
  71. {
  72. for(i = indexMid - (MaxOdd - 1) / 2; i <= indexMid + (MaxOdd - 1) / 2; i++)
  73. {
  74. putchar(A[i]);
  75. }
  76. }
  77. else
  78. {
  79. for(i = First - (MaxEven - 2) / 2; i <= First + 1 + (MaxEven - 2) / 2; i++)
  80. {
  81. putchar(A[i]);
  82. }
  83. }
  84. return 0;
  85. }
/*    长度为N(N很大)的字符串,求这个字符串里的最长回文子串。*/#include <stdio.h>#include <stdlib.h>#include <string.h>//第一类“12321”:中间是一个单独的字符int  FindLongPaliSubstr_Odd(const char A[], int * indexMid){    int i = 0, cnt = 0;//cnt表示前后移动位数    int MyMax = 0;    int lenOfA = strlen(A);    *indexMid = 0;    for(i = 1; i <= lenOfA - 2; i++)    {        cnt = 0;        while(i - cnt >= 0 && i + cnt <= lenOfA - 1 && A[i - cnt] == A[i + cnt])        {            cnt++;        }        cnt--;        //找到较大长度的回文字符串,保存中心字符的位置        if(MyMax < 2 * cnt + 1)        {            MyMax = 2 * cnt + 1;            *indexMid = i;        }    }    return MyMax;}//第二类“12321”:中间是两个相同的字符。int  FindLongPaliSubstr_Even(const char A[],int * First){    int i = 0, cnt = 0;//cnt表示前后移动位数    int MyMax = 0;    int lenOfA = strlen(A);    *First = 0;//中间两个相同字符的第一个字符位置    for(i = 0; i <= lenOfA - 2; i++)    {        if(A[i] == A[i + 1])        {            cnt = 1;            while(i - cnt >= 0 && (i + 1 + cnt) <= lenOfA - 1 && A[i - cnt] == A[i + 1 + cnt])            {                cnt++;            }            cnt--;            //找到较大长度的回文字符串,保存中心第一个字符的位置            if(MyMax < 2 * cnt + 2)            {                MyMax = 2 * cnt + 2;                *First = i;            }        }    }    return MyMax;}int main(void){    char A[] = "adfadfbadfdg12321fagage";    int indexMid = 0;    int First = 0;    int i = 0;    //两种类别的最长回文子串的长度    int MaxOdd = FindLongPaliSubstr_Odd(A, &indexMid);    int MaxEven = FindLongPaliSubstr_Even(A, &First);    printf("indexMid = %d\n", indexMid);    printf("First = %d\n", First);    //哪类比较大,输出哪一类的回文子串    if( MaxOdd > MaxEven)    {        for(i = indexMid - (MaxOdd - 1) / 2; i <= indexMid + (MaxOdd - 1) / 2; i++)        {            putchar(A[i]);        }    }    else    {        for(i = First - (MaxEven - 2) / 2; i <= First + 1 + (MaxEven - 2) / 2; i++)        {            putchar(A[i]);        }    }    return 0;}

3、数轴上从左到右有n各点a[0], a[1], ……,a[n -1],给定一根长度为L的绳子,求绳子最多能覆盖其中的几个点。

解:我对第3题的题解也是很常规,就是把相邻两个点的距离求出来,保存在一个数组arr[N]里面,从头到尾遍历数组arr[N],和直接选择排序差不多,写两个for循环,第一个for循环(外循环)中计数器i 表示连续线段的起点,第二个for循环(内循环)的计数器 j (i + 1)开始,依次累加Sum,若Sum > L,则记录点的个数(j - i)中的较大值max;其中,外循环,只要遇到的数比L大,就continue,内循环,只要遇到的数比L大,就break,这是因为长度为L的绳子是不可能覆盖这些点的,可以直接跳过!

如图:

my code:

[cpp] view plaincopyprint?
  1. /*
  2. 数轴上从左到右有n个点a[0],a[1],...,a[n - 1],给定一根长度为L的绳子,求绳子最多能覆盖其中几个点。
  3. */
  4. #include <stdio.h>
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #define N 8
  8. int MaxTimesOfL(int A[],int L)
  9. {
  10. int i = 0, j = 0;
  11. int *arr = (int *)malloc(sizeof(int) * (N - 1));
  12. memset(arr, 0, sizeof(int) * (N - 1));
  13. //初始化数组arr,两点间的距离为一个数组元素
  14. for(i = 0; i < N - 1; i++)
  15. {
  16. arr[i] = A[i + 1] - A[i];
  17. }
  18. //输出该数组
  19. for(i = 0; i < N - 1; i++)
  20. {
  21. printf("%-3d", arr[i]);
  22. }
  23. int MaxTimes = 0;
  24. int Sum = 0;
  25. //遍历找到覆盖的最多点数
  26. for(i = 0; i < N; i++)
  27. {
  28. if(arr[i] > L)//遇到比L大的数则跳过
  29. {
  30. continue;
  31. }
  32. Sum = arr[i];
  33. for(j = i + 1; j < N - 1; j++)
  34. {
  35. if(arr[j] > L)//遇到比L大的数则跳过,这一句对于程序来说加与不加都一样
  36. {
  37. break;
  38. }
  39. Sum += arr[j];
  40. if(Sum > L)
  41. {
  42. break;
  43. }
  44. }
  45. MaxTimes = (MaxTimes > (j - i)) ? MaxTimes : (j - i);
  46. }
  47. return (MaxTimes + 1);//因为是线段,所以要加1表示覆盖的点数
  48. }
  49. int main(void)
  50. {
  51. int A[] = {-1, 0, 3, 9, 11, 13, 14, 25};
  52. int L = 5;
  53. int result = MaxTimesOfL(A, L);
  54. printf("\nthe max times is %d\n", result);
  55. return 0;
  56. }
/*    数轴上从左到右有n个点a[0],a[1],...,a[n - 1],给定一根长度为L的绳子,求绳子最多能覆盖其中几个点。*/#include <stdio.h>#include <stdlib.h>#include <string.h>#define N 8int MaxTimesOfL(int A[], int L){    int i = 0, j = 0;    int *arr = (int *)malloc(sizeof(int) * (N - 1));    memset(arr, 0, sizeof(int) * (N - 1));    //初始化数组arr,两点间的距离为一个数组元素    for(i = 0; i < N - 1; i++)    {        arr[i] = A[i + 1] - A[i];    }    //输出该数组    for(i = 0; i < N - 1; i++)    {        printf("%-3d", arr[i]);    }    int MaxTimes = 0;    int Sum = 0;    //遍历找到覆盖的最多点数    for(i = 0; i < N; i++)    {        if(arr[i] > L)//遇到比L大的数则跳过        {            continue;        }        Sum = arr[i];        for(j = i + 1; j < N - 1; j++)        {            if(arr[j] > L)//遇到比L大的数则跳过,这一句对于程序来说加与不加都一样            {                break;            }            Sum += arr[j];            if(Sum > L)            {                break;            }        }        MaxTimes = (MaxTimes > (j - i)) ? MaxTimes : (j - i);    }    return (MaxTimes + 1);//因为是线段,所以要加1表示覆盖的点数}int main(void){    int A[] = {-1, 0, 3, 9, 11, 13, 14, 25};    int L = 5;    int result = MaxTimesOfL(A, L);    printf("\nthe max times is %d\n", result);    return 0;}

最后贴一下试题: