微软面试题——整数升序数组、数M,输出和为M的两个数组元素

问题:输入一个已经按升序排序过的数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。

要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字M,输出任意一对即可。例如输入数组12471115和数字15。由于4+11=15,因此输出411

一般思路

1)让指针指向数组的头部和尾部,相加,如果小于M,则增大头指针,如果大于则减小尾指针

2)退出的条件,相等或者头部=尾部

代码如下:

void function(int a[],int n,int M)
{
      int i=0,j=n-1;
  while(i!=j){
           if(a[i]+a[j]==M){
      printf("%d,%d",a[i],a[j]);
                  break;
    }
    a[i]+a[j]>M?j--:i++;
  }
}

 

推广:

       如果数组中的数是无序的,如何在O(n)的时间复杂度内,找出这两个数。

分析:关于算法,在笔者看来,工程中要一个问题的复杂度可以分为三个部分:时间复杂度,空间复杂度,逻辑复杂度。在这三种类型的复杂度中,要降低任何一种复杂度都可以通过牺牲另外两个复杂度获得。时间复杂度和空间复杂度相信大家都不陌生,逻辑复杂度主要包括代码的逻辑性和所涉及的数据结构,比如排序,可以用线性的数据结构实现,也可以用树型的数据结构实现,由于树性结构比线性结构逻辑性要强,所以我们可以通过平衡二叉树,红黑树降低排序某个方面时间复杂度。

本题思路:

        以牺牲空间复杂度来降低时间复杂度。所谓牺牲空间复杂度,就是要开辟一个内容空间来保存某些对于求解有帮助的信息。正如在动态规划中,牺牲空间复杂度就是开辟空间来保存重叠子问题的解。回到本题中,要求时间复杂度为O(n),即每个数组元素只遍历一遍,如何在遍历到4的时候判定是否存在11,让两个数的和为15呢?那么就需要保存数组中是否有11这个数,这就是我们牺牲空间复杂度所要保存的东西。要保存是否存在某个数,我们很自然就想到散列表,下面就具体说一下如何用空间复杂度换取时间复杂度。

同样输入数组21411715和数字15

        从数字15入手,两个数的和为15,共有多少组呢?015,114,213,…,78。定义大小为15/2+1=8HashT统计某个数出现的次数,现在要完成的就是如何将015,114,213,…,78通过Hash函数映射到同位置。如a如何通过Hash函数映射,最简单的方法,如果a小于等于15/2=7,则Hasha=a;如果a大于15/2=7,则Hasha=15-a

代码如下:

void function(int a[],int n,int M)
{
   int hash[M/2+1]={0};
   for(int i=0,i<n;i++)
   {
      if(a[i]<=M/2)
        {
          if(1==hash(a[i]))
            printf("%d,%d \n",a[i],a[15-i]);
          }
      if(a[i]>M/2&&a[i]<=M)
          {
          if(1==hash(a[15-i]))
            printf("%d,%d \n",a[i],a[15-i]);
            }
     }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值