微软十五道面试题( 自己的实现,求更有解~~~~ O(∩_∩)O~ )

1、有一个整数数组,请求出两两之差绝对值最小的值,
记住,只要得出最小值即可,不需要求出是哪两个数。

int num =MAXNUM;        //! 可否有优化?

int temp;

for( int i = 0; i < maxsize; i++ )

{

for ( int j = i + 1 ; j < maxsize; j++)

{

  temp = fabs( a[i]  a[j]  ;

  num =  num> temp  temp :num ;

}

}

我们可以看一下上面的复杂度:应该是:1+2+…+(maxsize-1),所以是O(n^2 );

但是if我们先排序一下(优化算法可以用STL的nth_element处理),然后只要遍历一次,两两比较就可以了!

CODE:

int num = MAXNUM;

int temp;

nth_element( a, a + mid, a + maxsize);   //!sort…

for( int  i = 0; i < maxsize- 1; i++ )

{

      temp = abs( a[i] – a[i+1] );

      num =  num > temp ? temp ,num;

}

                             

可以知道:nth_element的时间复杂度是<O(n^2)的,后面的for也就是O(n),所以整体放入复杂度就是接近O(n),所以效率更高!

 

2、写一个函数,检查字符是否是整数,如果是,返回其整数值。
(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?)

(1).

#include <stdio.h>

#include <math.h>

#include <string.h>

int main()

{

      char str[] = "34567";

      int strSize = strlen( str );

      long num = 0;

      for(  int i 0;  strSize;  i++)

      {

             if( ! ( str[i] >= '0' && str[i] <='9'  ) )

             {

                    printf( "no\n" );

                    goto end;

             }

             else

             {

                    num += long( pow( 10,  strSize - i - 1 )*  int( str[i] - '0' ));

             }

      }

      printf("num = %ld\n", num);

end:

      return 0;

}

( 2 ).

long  strToLong( char * str )

{

for( int i = 0; i < strlen( str);  i++ )

num += ( long )( pow( strlen( str ) – 1 - i ) * ( int )(str[i] – ‘0’ ) );

return num;

}

3、给出一个函数来输出一个字符串的所有排列。( 全排列 )

#include <stdio.h>

#include <string.h>

void swapElem( char * c1, char * c2)    //! 交换两个元素

{

      char temp;

      temp  = *c1;

      *c1   = *c2;

      *c2   = temp;

}

void permSort( char str[], int maxsize, int startIndex)   //! 全排列

{

      if ( startIndex == maxsize - 1)    //!最后只剩下一个元素的遍历咯,就输出吧!

      {

             puts( str );

             return;

      }

      for ( int i = startIndex; i < maxsize; i++)          //!

      {

             swapElem( &str[i], &str[startIndex]);          

  //! 注意此处交换后面的几个元素,需要用递归

             permSort( str, maxsize, startIndex + 1 );

             swapElem( &str[startIndex], &str[i]);            //! 记得要交换回来!!!

               

}

int main()

{

      char str[] = "12345";

      int maxsize = strlen( str );

      permSort( str, maxsize, 0 );

      return 0;

}

 

4、请编写实现malloc()内存分配函数功能一样的代码。
给出一个函数来复制两个字符串A和B。字符串A的后几个字节和字符串B的前几个字节重叠。

 //! 这个我真不会!求高人!!!

 //!???????????????????????????????????????????????????????????????????

 

5、怎样编写一个程序,把一个有序整数数组放到二叉树中?( 采用递归方法 )

pTree  t;   //!给一个全局的tree来先

void   putInBinTree( inta[], int low, int high, pTree t )

{

      if( low >= high )

{

  t->value = a[low];

  t->lChild = NULL;

  t->rChild = NULL;

  return;

}

int  mid = ( low + high ) / 2;

t->value = a[mid];

if( mid – 1 >= low )

{

putInBinTree( a, low, mid – 1, t->lChild);

}

if( mid + 1 <= high )

{

putInBinTree( a, mid + 1, high , t->rChild);

 }

}

 

6、怎样从顶部开始逐层打印二叉树结点数据?请编程。  (就是层次遍历而已、、、 )

//!  ( tail – head + MaxNum ) % MaxNum== 实际元素个数

treeNode queue[100];   //! 节点队列

int head = 0;

int tail = 1;

queue[tail++] = rootTree;  //! 先把头放进去

while( !queue.isEmpty())

{

      printf(“%d”, queue[++head]->value);

      if(queue[head]->lChild != NULL )

{

             queue[tail++] = queue[head]->lChild;

      }

      if(queue[head]->rChild != NULL )

{

queue[tail++] = queue[head]->rChild;

}

}

 

7、怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)?

当然对于此题来说:我的思路是我们需要一个栈空间来做temp,然后出栈就倒置了,呵呵~

例如现在有一个链表pLinkList   ls;   //! 前提是有头链表

void  reverseLinkList( pLinkList ls)

{

      pLinkList  head = NULL;

linkList  tempStack;

      int       top = -1;

      head = ls->next;

      while( head != NULL )

{

  tempStack[++top] = head;

  head = head->next;

}

ls->next = head;

While( top >= 0 )

{

  head = tempStack[top--];

  head->next = NULL;

  head = head->next;

}

}

 

>>>当然我现在又想到另一种方法,就是不需要额外的栈空间的,利用链表插入法:遍历每个元素都往头head后面插入,那么完成后就是倒置的了,呵呵~~~

pLinkList newHead = NULL;

pLinkList head = ls->next;

while( head != NULL )

{

      newHead->next = head;

      head = head->next;

}

//!那么最后 newHead 就是倒置的链表咯

 

8、请编写能直接实现int atoi(const char * pstr)函数功能的代码。

 

int  atoi( char * pstr )

{

      const char * strTemp = pstr;

      assert(  strTemp != NULL );   //!先要断言不是NULL

      int num = 0;

      int size = strlen ( strTemp );

      int i= 0;

      while( strTemp[i] )

      {

             assert( strTemp[i] >= '0' &&  strTemp[i]<= '9' ); 

 //! 断言是数字字符

             num += (int)( pow( 10, size - i - 1 ) * ( strTemp[i] - '0' ));

             i++;

      }

      return num;

}

9、编程实现两个正整数的除法

编程实现两个正整数的除法,当然不能用除法操作符。
//! 这一题有问题!希望有好解!

unsigned int div (unsigned int a, unsigned int b)
{
   int i;
   unsigned int m = 0;
   for (i = 1; i <= 32; i++)
   {
           m = (m << 1) | (a >> 31);
           a = a << 1;
           if (m >= b)
           {
               m = m - b;
               a = a + 1;
           }
   }
 
   return a;
}

 

10、在排序数组中,找出给定数字的出现次数
比如 [1, 2, 2, 2, 3] 中2的出现次数是3次。

//! 我的思路是当然先要二分法找到此数在处理(我们知道在排序好的查找元素二分法最快 )

int  getCount( intarray[],  int num, int size )

{

      int low = 0;

      int high = size - 1;

      int count = 0;

      int mid;

      while ( low <= high )

      {

             mid =  ( low + high ) / 2;

 

             if( array[mid]  > num )

             {

                    high = mid - 1;

             }

             else if(array[mid]  < num )

             {

                    low = mid + 1;

             }

             else

             {

                    break;   //! mid is myfood!

             }

      }

      low  = mid;

      high = mid + 1;

      while( low >=0 && array[low] == num )

      {

             count++;

             low--;

      }

      while( high <= (size - 1) && array[high] == num )

      {

             count++;

             high++;

      }

      return count;

}

 

 

11、平面上N个点,每两个点都确定一条直线,
求出斜率最大的那条直线所通过的两个点(斜率不存在的情况不考虑)。时间效率越高越好。

斜率公式是:k = (y2 – y1) / (x2 – x1);

我的思路是:先按照X将所有的point进行排序,然后对他们进行遍历,由于数学上有讲过-àif排序为A,B,C那么AB和BC中必然有一个比AC斜率大,一个比他小,所以需要进行计算,然后遍历推进直到点结束,最后找到最大!不知道还有么有更好的办法(此办法不能保证是百分百正确,只是自己的想法而已、、、 )

首先我们假设已经有了point的结构体:

typedef   structpoint

{

      int  s_x;

          int  s_y;s

}point;

point  allPoint[N];   //! 有N个点

void  getMaxSlopePoint(point  allPoint[]  )

{

      point A, B, C;

      double maxSlope = 0;

      point p1, p2;

      //! 此处的排序就不说了

      for(  i = 0;  i <N - 2;  i++   //! 由于下面i+2 所以遍历到N-2就OK了!!!

{

  A = allPoint[i];

  B = allPoint[i+1];

  C = allPoint[i+2];

  double  Kab = ( A.y – B.y) / ( A.x – B.x );

  double  Kbc = ( B.y – C.y) / ( B.x – C.x );

  if( Kab > Kbc )
             {

        maxSlope = Kab;

        p1 = a;

        p2 = b;

}

else

{

        maxSlope = Kbc;

        p1 = b;

        p2 = c;

}

}

}

 

 

12、一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。
请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。
注意:
- 5个数值允许是乱序的。比如: 8 7 5 0 6
- 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4
- 0可以多次出现。
- 复杂度如果是O(n2)则不得分。

>>>我们将题目简化为:有一个5元素的数组,比较是否相邻(当然要满足上面的条件! )

CODE:

基本思想:先将它们从小到大排序,我们只对于非0的元素进行判断,因为0可以代表任何元素!那么返回false的条件是:有重复的数;非0元素之间的最大差值已经超过4了!然后就都是可以的!时间复杂度是O( nlog(n) )

操作方法是:把他们正确的放进数组b中,if不满足上面条件的是放不进去得!相当于第一个非0元素是一个标准,然后后面的非0元素的放入是值想减放到指定的空间,if空间不满足,那么就是返回false!

bool judgeFun( int num[], int size)     //! 注意这里的num是已经选出的5个数

{

      int b[5] = { 0, 0, 0, 0, 0};      //! five space is ok!

      int i = 0;

      nth_element( num, num[(int)size/2],num[size-1] ); //! STL sort

 //! sort first:时间复杂度是:O(nlog(n) )

      b[0] =num[i];                  //! the first num

      i++;

      while( i < size)                //! 复杂度是O( n )

      {

             if ( num[i] - b[0] > 4)     //! 说明不在相邻的5的范围内,false

             {

                    return false;

             }

 

             if ( b[num[i] - b[0]] != 0 ) 

//! 说明此处已经有了元素进入,那么也就是说有重复元素,所以不可能是相邻的呗!

             {

                    return false;

             }

             b[num[i] - b[0]] = num[i];

             i++;

      }

      return true;

}

 

13、设计一个算法,找出二叉树上任意两个结点的最近共同父结点。
复杂度如果是O(n2)则不得分。

我的思路:

      >>>If说:数据结构是我们自己可以定义的话,那么我觉得子女可以有一个域保存parent,那么我们就可以分别先求出两个子节点的深度,较深的先向上走直到与浅的一样,再共同向上,肯定能找到,这样复杂度就是O(n),但是貌似这一题没有给我们这么优势的条件,所以怎么办呢?????

      >>>然后还有一个想法就是说:从根节点开始,向下遍历,直到找到两个点,记录标号路径,然后比较就可以得到答案,时间复杂度是O(n),但是需要空间的支持!

      >>>其实这一题就是LCA问题             ( 最近公共祖先问题lowestcommon ancestor),所谓的思想就是说:使用后序遍历,一旦察觉到两个子节点在A的二叉上,那么这个A就是最小祖先!有一个特殊情况就是说:if两个子节点在同一个叉上,也就是说一个可能是另一个的父亲,那么只要找到爷爷就OK呵呵!O(∩_∩)O~ 至于为什么要用后序遍历,那么我们知道,后序遍历parent是最后出来的,那么一旦读到parent的时候就可以判断是不是已经满足两个孩子的条件咯!

CODE略!

 

14、一棵排序二叉树,令 f=(最大值+最小值)/2,
设计一个算法,找出距离f值最近、大于f值的结点。
复杂度如果是O(n2)则不得分。

//!     首先我们需要找到f的值,其实这个还是很好求的:从root开始,遍历左孩子直到NULL,min找到,还是从root开始遍历右孩子直到NULL,找到max;那么f我们现在求到了!

//!     然后再从root开始比较,if比此时的节点小那么就是记录此点,然后与左孩子比较,if比他大,那么往右孩子找,直到NULL;( 所以记录点是很重要的! )

 

//!前面找f的过程很简单,就省略,传递参数f过去

//! 下面就是递归找合适的元素!

Node  getNode(pTree  t, double f )

{

      if( f >= t->value )

      {

             if( t->rChild == NULL )

             {

                    return t->parent;  //!找到???

}

return  getNode( t->rChild, f);

}

else

{

  if( t->lChild = NULL)

      {

        return  t; //! 找到

}

 

return  getNode( t->lChild, f);

}

}

 

 

15、一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。
设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。
复杂度最好是O(n),如果是O(n2)则不得分。

//! 首先我们还是要排序呀!

//!然后我的想法是,设置一个low和一个high的标号分别从第一位和最后以为开始靠拢性遍历,以low位数为基准(当然以高位也是一样的),寻找符合N+1条件匹配的high数,我们知道,既然是排序(从小到大 )的,if low匹配的数是high,那么low+1的匹配的数如果存在必然是<high,不然就不可能满足N+1的条件了是吧,这是小学数学知识!经过分析,知道主要时间在排序上,是O(nlog(n) );--àif用归并算法,可以接近O(n)/

CODE:

void   findNum( int num[],int size )

{

      int  low = 0, high = size – 1;

      while( low < high ) 

      {

             while( num[low] + num[high]  > N +1 && low <high 

             //!还很大,所以high还要再小一点才可以

{

   high--;

}

while( num[low] + num[high] < N + 1&& low < high) 

//! 说明low元素是没有可以匹配的

{

            low++;

}

if( num[low] + num[high] == N + 1 && low < high)

{

            //! 找到一对咯~~~

            low++;

            high--;

}

}

}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值