面试总结3

来源:互联网 发布:足球数据库哪个好 编辑:程序博客网 时间:2024/04/28 02:29

strcpy和memcpy的区别

strcpy和memcpy都是标准C库函数,它们有下面的特点。
strcpy提供了字符串的复制。即strcpy只用于字符串复制,并且它不仅复制字符串内容之外,还会复制字符串的结束符。

已知strcpy函数的原型是:char* strcpy(char* dest, const char* src);
memcpy提供了一般内存的复制。即memcpy对于需要复制的内容没有限制,因此用途更广。
void *memcpy( void *dest, const void *src, size_t count );

char * strcpy(char * dest, const char * src) // 实现src到dest的复制{  if ((src == NULL) || (dest == NULL)) //判断参数src和dest的有效性  {       return NULL;  }  char *strdest = dest;        //保存目标字符串的首地址  while ((*strDest++ = *strSrc++)!='\0'); //把src字符串的内容复制到dest下  return strdest;}void *memcpy(void *memTo, const void *memFrom, size_t size){  if((memTo == NULL) || (memFrom == NULL)) //memTo和memFrom必须有效         return NULL;  char *tempFrom = (char *)memFrom;             //保存memFrom首地址  char *tempTo = (char *)memTo;                  //保存memTo首地址        while(size -- > 0)                //循环size次,复制memFrom的值到memTo中         *tempTo++ = *tempFrom++ ;    return memTo;}


?

strcpy和memcpy主要有以下3方面的区别。
1、复制的内容不同。strcpy只能复制字符串,而memcpy可以复制任意内容,例如字符数组、整型、结构体、类等。
2、复制的方法不同。strcpy不需要指定长度,它遇到被复制字符的串结束符"\0"才结束,所以容易溢出。memcpy则是根据其第3个参数决定复制的长度。
3、用途不同。通常在复制字符串时用strcpy,而需要复制其他类型数据时则一般用memcpy

第21题
2010年中兴面试题
编程求解:
输入两个整数 n 和 m,从数列1,2,3.......n 中 随意取几个数,
使其和等于 m ,要求将其中所有的可能组合列出来.
//此题与第14题差不多,在次不做过多解释。

#include<list>  #include<iostream>  using namespace std;    list<int>list1;  void find_factor(int sum, int n)   {      // 递归出口      if(n <= 0 || sum <= 0)          return;            // 输出找到的结果      if(sum == n)      {          // 反转list          list1.reverse();          for(list<int>::iterator iter = list1.begin(); iter != list1.end(); iter++)              cout << *iter << " + ";          cout << n << endl;          list1.reverse();          }            list1.push_front(n);      //典型的01背包问题      find_factor(sum-n, n-1);   //放n,n-1个数填满sum-n      list1.pop_front();      find_factor(sum, n-1);     //不放n,n-1个数填满sum   }    int main()  {      int sum, n;      cout << "请输入你要等于多少的数值sum:" << endl;      cin >> sum;      cout << "请输入你要从1.....n数列中取值的n:" << endl;      cin >> n;      cout << "所有可能的序列,如下:" << endl;      find_factor(sum,n);      return 0;  } 

第25题:
写一个函数,它的原形是int continumax(char *outputstr,char *intputstr)
功能:
在字符串中找出连续最长的数字串,并把这个串的长度返回,
并把这个最长数字串付给其中一个函数参数outputstr所指内存。
例如:"abcd12345ed125ss123456789"的首地址传给intputstr后,函数将返回9,
outputstr所指的值为123456789

//leeyunce
这个相对比较简单,思路不用多说,跟在序列中求最小值差不多。未经测试。有错误欢迎指出

int continumax(char *outputstr, char *intputstr){    int i, maxlen = 0;    char * maxstr = 0;    while (true)    {            while (intputstr && (*intputstr<'0' || *intputstr>'9')) //skip all non-digit characters        {                intputstr++;        }        if (!intputstr) break;        int count = 0;        char * tempstr = intputstr;        while (intputstr && (*intputstr>='0' && *intputstr<='9')) //OK, these characters are digits        {                count++;            intputstr++;        }        if (count > maxlen)        {                maxlen = count;            maxstr = tempstr;        }    }    for (i=0; i<maxlen; i++)    {            outputstr[i] = maxstr[i];    }    outputstr[i] = 0;    return maxlen;}

26.左旋转字符串
  题目:
  定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。
    如把字符串abcdef左旋转2位得到字符串cdefab。请实现字符串左旋转的函数。
    要求时间对长度为n的字符串操作的复杂度为O(n),辅助内存为O(1)。

分析:如果不考虑时间和空间复杂度的限制,
最简单的方法莫过于把这道题看成是把字符串分成前后两部分,
通过旋转操作把这两个部分交换位置。

于是我们可以新开辟一块长度为n+1的辅助空间,
把原字符串后半部分拷贝到新空间的前半部分,在把原字符串的前半部分拷贝到新空间的后半部分。
不难看出,这种思路的时间复杂度是O(n),需要的辅助空间也是O(n)。

把字符串看成有两段组成的,记位XY。左旋转相当于要把字符串XY变成YX。
我们先在字符串上定义一种翻转的操作,就是翻转字符串中字符的先后顺序。把X翻转后记为XT。显然有

(XT)T=X。
我们首先对X和Y两段分别进行翻转操作,这样就能得到XTYT。
接着再对XTYT进行翻转操作,得到(XTYT)T=(YT)T(XT)T=YX。正好是我们期待的结果。

分析到这里我们再回到原来的题目。我们要做的仅仅是把字符串分成两段,
第一段为前面m个字符,其余的字符分到第二段。
再定义一个翻转字符串的函数,按照前面的步骤翻转三次就行了。
时间复杂度和空间复杂度都合乎要求。

#include "string.h"// Move the first n chars in a string to its end char* LeftRotateString(char* pStr, unsigned int n){    if(pStr != NULL)    {        int nLength = static_cast<int>(strlen(pStr));        if(nLength > 0 || n == 0 || n > nLength)        {            char* pFirstStart = pStr;            char* pFirstEnd = pStr + n - 1;            char* pSecondStart = pStr + n;            char* pSecondEnd = pStr + nLength - 1;                        // reverse the first part of the string            ReverseString(pFirstStart, pFirstEnd);            // reverse the second part of the strint            ReverseString(pSecondStart, pSecondEnd);            // reverse the whole string            ReverseString(pFirstStart, pSecondEnd);        }    }        return pStr;}// Reverse the string between pStart and pEndvoid ReverseString(char* pStart, char* pEnd){    if(pStart == NULL || pEnd == NULL)    {        while(pStart <= pEnd)        {            char temp = *pStart;            *pStart = *pEnd;            *pEnd = temp;                        pStart ++;            pEnd --;        }    }}

27.跳台阶问题
题目:一个台阶总共有n级,如果一次可以跳1级,也可以跳2级。
求总共有多少总跳法,并分析算法的时间复杂度。

首先我们考虑最简单的情况。如果只有1级台阶,那显然只有一种跳法。
如果有2级台阶,那就有两种跳的方法了:一种是分两次跳,每次跳1级;另外一种就是一次跳2级。

现在我们再来讨论一般情况。我们把n级台阶时的跳法看成是n的函数,记为f(n)。
当n>2时,第一次跳的时候就有两种不同的选择:一是第一次只跳1级,
此时跳法数目等于后面剩下的n-1级台阶的跳法数目,即为f(n-1);
另外一种选择是第一次跳2级,此时跳法数目等于后面剩下的n-2级台阶的跳法数目,即为f(n-2)。
因此n级台阶时的不同跳法的总数f(n)=f(n-1)+(f-2)。

我们把上面的分析用一个公式总结如下:

        /  1                          n=1
f(n)=      2                          n=2
        /  f(n-1)+(f-2)               n>2

分析到这里,相信很多人都能看出这就是我们熟悉的Fibonacci序列。


int jump_sum(int n)  //递归版本{    assert(n>0);    if (n == 1 || n == 2) return n;    return jump_sum(n-1)+jump_sum(n-2);}int jump_sum(int n) //迭代版本{    assert(n>0);    if (n == 1 || n == 2) return n;    int an, an_1=2, an_2=1;    for (; n>=3; n--)    {            an = an_2 + an_1;        an_2 = an_1;        an_1 = an;    }    return an;}

28.整数的二进制表示中1的个数
题目:输入一个整数,求该整数的二进制表达中有多少个1。
例如输入10,由于其二进制表示为1010,有两个1,因此输出2。

分析:
这是一道很基本的考查位运算的面试题。
包括微软在内的……


一个很基本的想法是,我们先判断整数的最右边一位是不是1。
接着把整数右移一位,原来处于右边第二位的数字现在被移到第一位了,
再判断是不是1。
这样每次移动一位,直到这个整数变成0为止。
现在的问题变成怎样判断一个整数的最右边一位是不是1了。

很简单,如果它和整数1作与运算。由于1除了最右边一位以外,其他所有位都为0。
因此如果与运算的结果为1,表示整数的最右边一位是1,否则是0。*/

得到的代码如下:

int NumberOf1_Solution1(int i){      int count = 0;      while(i)      {            if(i & 1)                  count ++;            i = i >> 1;      }      return count;}

这个思路当输入i是正数时没有问题,但当输入的i是一个负数时,
不但不能得到正确的1的个数,还将导致死循环。

以负数0x80000000为例,右移一位的时候,
并不是简单地把最高位的1移到第二位变成0x40000000,
而是0xC0000000。这是因为移位前是个负数,仍然要保证移位后是个负数,
因此移位后的最高位会设为1。
如果一直做右移运算,最终这个数字就会变成0xFFFFFFFF而陷入死循环。

为了避免死循环,我们可以不右移输入的数字i。
首先i和1做与运算,判断i的最低位是不是为1。
接着把1左移一位得到2,再和i做与运算,就能判断i的次高位是不是1……
这样反复左移,每次都能判断i的其中一位是不是1。基于此,我们得到如下代码:

int NumberOf1_Solution2(int i){      int count = 0;      unsigned int flag = 1;      while(flag)      {            if(i & flag)                  count ++;            flag = flag << 1;      }      return count;}

38.
百度面试:
1.用天平(只能比较,不能称重)从一堆小球中找出其中唯一一个较轻的,使用x 次天平,
最多可以从y 个小球中找出较轻的那个,求y 与x 的关系式。
ANSWER:
x=1, y=3: if a=b, c is the lighter, else the lighter is the lighter...
do this recursively. so y=3^x;

2.有一个很大很大的输入流,大到没有存储器可以将其存储下来,
而且只输入一次,如何从这个输入流中随机取得m 个记录。
ANSWER

That is, keep total number count N. If N<=m, just keep it.
For N>m, generate a random number R=rand(N) in [0, N), replace a[R] with new number if R falls in [0, m).


3.大量的URL 字符串,如何从中去除重复的,优化时间空间复杂度
ANSWER
1. Use hash map if there is enough memory.
2. If there is no enough memory, use hash to put urls to bins, and do it until we can fit the bin into memory.



39.
网易有道笔试:
(1).
求一个二叉树中任意两个节点间的最大距离,
两个节点的距离的定义是这两个节点间边的个数,
比如某个孩子节点和父节点间的距离是1,和相邻兄弟节点间的距离是2,优化时间空间复
杂度。
ANSWER
Have done this.
(2).
求一个有向连通图的割点,割点的定义是,如果除去此节点和与其相关的边,
有向图不再连通,描述算法。
ANSWER
Do dfs, record low[i] as the lowest vertex that can be reached from i and i’s successor nodes. For each edge i, if low[i] = i and i is not a leaf in dfs tree, then i is a cut point. The other case is the root of dfs, if root has two or more children ,it is a cut point.
/*** g is defined as: g[i][] is the out edges, g[i][0] is the edge count, g[i][1...g[i][0]] are the other end points.*/int cnt = 0;int visited[MAX_NUM];int lowest[MAX_NUM];void getCutPoints(int *g[], int cuts[], int n) {  memset(cuts, 0, sizeof(int)*n);  memset(visited, 0, sizeof(int)*n);  memset(lowest, 0, sizeof(int)*n);  for (int i=0; i<n; i++) {    if (visited[i] == 0) {      visited[i] = ++cnt;      dfs(g, cuts, n, i, i);  }}int dfs(int *g[], int cuts[], int n, int s, int root) {  int out = 0;  int low = visit[s];  for (int i=1; i<=g[s][0]; i++) {    if (visited[g[s][i]] == 0) {      out++;      visited[g[s][i]] = ++cnt;      int clow = dfs(g, cuts, n, g[s][i], root);      if (clow < low) low = clow;    } else {      if (low > visit[g[s][i]]) {        low = visit[g[s][i]];      }    }  }  lowest[s] = low;  if (s == root && out > 1) {    cuts[s] = 1;  }  return low;}



40.百度研发笔试题
引用自:zp155334877
1)设计一个栈结构,满足一下条件:min,push,pop操作的时间复杂度为O(1)。

2)一串首尾相连的珠子(m个),有N种颜色(N<=10),
设计一个算法,取出其中一段,要求包含所有N中颜色,并使长度最短。
并分析时间复杂度与空间复杂度。

3)设计一个系统处理词语搭配问题,比如说 中国 和人民可以搭配,
则中国人民 人民中国都有效。要求:

  *系统每秒的查询数量可能上千次;
  *词语的数量级为10W;
  *每个词至多可以与1W个词搭配

当用户输入中国人民的时候,要求返回与这个搭配词组相关的信息。

此题的第1小题,即是借助辅助栈,保存最小值,
且随时更新辅助栈中的元素。
如先后,push 2 6 4 1 5
 stack A  stack B(辅助栈)

4:  5       1      //push 5,min=p->[3]=1     ^
3:  1       1      //push 1,min=p->[3]=1     |   //此刻push进A的元素1小于B中栈顶元素2
2:  4       2      //push 4,min=p->[0]=2     |
1:  6       2      //push 6,min=p->[0]=2     |
0:  2       2      //push 2,min=p->[0]=2     |

push第一个元素进A,也把它push进B,
当向Apush的元素比B中的元素小,  则也push进B,即更新B。否则,不动B,保存原值。
向栈A push元素时,顺序由下至上。
辅助栈B中,始终保存着最小的元素。

然后,pop栈A中元素,5 1 4 6 2
     A       B ->更新  
4:   5       1    1     //pop 5,min=p->[3]=1      |
3:   1       1    2     //pop 1,min=p->[0]=2      |
2:   4       2    2     //pop 4,min=p->[0]=2      |
1:   6       2    2     //pop 6,min=p->[0]=2      |
0:   2       2    NULL  //pop 2,min=NULL          v

当pop A中的元素小于B中栈顶元素时,则也要pop B中栈顶元素。


2)一串首尾相连的珠子(m个),有N种颜色(N<=10),
设计一个算法,取出其中一段……
2.就是给一个很长的字符串str 还有一个字符集比如{a,b,c} 找出str里包含{a,b,c}的最短子串。
要求O(n)?
比如,字符集是a,b,c,字符串是abdcaabcx,则最短子串为abc

ANSWER
Use a sliding window and a counting array, plus a counter which monitors the num of zero slots in counting array. When there is still zero slot(s), advance the window head, until there is no zero slot. Then shrink the window until a slot comes zero. Then one candidate segment of (window_size + 1) is achieved. Repeat this. It is O(n) algorithm since each item is swallowed and left behind only once, and either operation is in constant time.
int shortestFullcolor(int a[], int n, int m) {
  int c[m], ctr = m;
  int h=0, t=0;
  int min=n;
  while (1) {
     while (ctr > 0 && h<n) {
       if (c[a[h]] == 0) ctr --;
       c[a[h]] ++;
       h++;
     }
     if (h>=n) return min;
     while (1) {
       c[a[t]] --;
       if (c[a[t]] == 0) break;
       t++;
     }
     if (min > h-t) min = h-t;
     t++; ctr++;
  }
}

3.
可以建立一个RDF文件,利用protege 4.0。或者自己写的RDF/XML接口也行。
在其中建立两个“描述对象”一个是国家,一个是人民。 国家之下建立一个中国,
人民。并且在关系中建立一个关系:对每个存在的国家,都have人民。
这样,每当用户输入这两个词的时候,
就利用语义框架/接口来判断一下这两个词汇的关系,返回一个值即可。

--贝叶斯分类--
其实贝叶斯分类更实用一些。 可以用模式识别的贝叶斯算法,
写一个类并且建立一个词汇-模式的表。
这个表中每个模式,也就是每个词汇都设一个域,可以叫做most-fitted word,
然后对这个分类器进行训练。

这个训练可以在初期设定一些关联词汇;也可以在用户每次正确输入查询的时候来训练。通过训练,每个单

词对应出现概率最高的单词设到最适合域里面。
然后对于每个词,都返回最适合的单词。

转自:http://blog.csdn.net/v_JULY_v/article/details/6126444


原创粉丝点击