【C/C++面试】数组篇

本文详细介绍了C/C++中数组的各种操作,包括数组求和、求最大值和最小值、寻找主元素、计算最短距离等经典算法。通过递归和分治策略解决数组问题,并探讨了数组的合并、重组和旋转等实际编程应用场景。
摘要由CSDN通过智能技术生成
 
  C/C++面试,数组相关的题目十分重要。笔者根据上海三思、心动网络等公司笔试面试题来分析, 本文罗列了一些常见的面试题,仅供参考,如果您有更好的题目或者想法,欢迎留言讨论。目前有以下18道题目,如有好的题目,随时更新。
  •  数组求和
  • 求数组中的最大值和最小值
  • 求数组中的最大值和次大值
  • 求数组中出现次数超过一半的元素
  • 求数组中元素的最短距离
  • 求两个有序数组的共同元素
  • 求三个数组的共同元素
  • 找出数组中唯一重复的元素
  • 找出出现奇数次的元素
  • 求数组中满足给定和的数对
  • 最大子段和
  • 最大子段积
  • 数组循环移位
  • 字符串逆转
  • 组合问题
  • 合并两个数组
  • 重排问题
  • 找出绝对值最小的元素
1.数组求和 
    给定一个含有n个元素的整型数组a,求a中所有元素的和。可能您会觉得很简单,是的,的确简单,但是为什么还要说呢,原因:这道题要求用递归,只用一行代码。
分析

    简单说一下,两种情况:
    1. 如果数组元素个数为0,那么和为0;
    2. 如果数组元素个数为n,那么先求出前n-1个元素之和,再加上a[n - 1]即可;
代码
  1. // 数组求和
  2. int sum(int*a, int n)
  3. {
  4.      return n ==0?: sum(a, n -1) + a[-1];
  5. }

求数组的最大值和最小值
    给定一个含有n个元素的整型数组a,求a中的最大值和最小值。
分析

   常规的做法是遍历一次,分别求出最大值和最小值,事实上,至多3|n/2|(||代表向下取整)就足以找出最小值和最大值。做法是:记录比较过程中遇到的最小值和最大值。我们并不是将每一个输入元素与当前的最大值和最小值进行比较(这样做的代价是每个元素需要两次比较),而是成对的处理元素。先将一对输入元素进行比较,然后把较小者与当前最小值进行比较,把较大者与当前最大值比较,因此每两个元素比较3次。
   如何假定当前最小值和最大值的初始值依赖于n是奇数还是偶数。如果n是奇数,就将最小值和最大值都设为第一个元素的值,然后成对的处理余下的元素。如果n是偶数,就对前两个元素做一次比较,以决定最小值和最大值的初值,然后如同n是奇数的情形一样,成对的处理余下的元素。

   但是这里要说的是分治法,将数组分成左右两部分,先求出左半部分的最大值和最小值,再求出右半部分的最大值和最小值,然后综合起来求总体的最大值和最小值。这是个递归的过程,对于划分后的左右两部分,同样重复这个过程,直到划分区间内只剩下一个元素或者两个元素。
代码

  1. // 求数组的最大值和最小值,返回值在maxValue和minValue
  2. void MaxandMin(int *a, int l, int r, int& maxValue, int& minValue)
  3. {
  4.     if(== r) // l与r之间只有一个元素
  5.     {
  6.         maxValue = a[l] ;
  7.         minValue = a[l] ;
  8.         return ;
  9.     }

  10.     if(+ 1 == r) // l与r之间只有两个元素
  11.     {
  12.         if(a[l] >= a[r])
  13.         {
  14.             maxValue = a[l] ;
  15.             minValue = a[r] ;
  16.         }
  17.         else
  18.         {
  19.             maxValue = a[r] ;
  20.             minValue = a[l] ;
  21.         }
  22.         return ;
  23.     }

  24.     int m = (+ r) / 2 ; // 求中点

  25.     int lmax ; // 左半部份最大值
  26.     int lmin ; // 左半部份最小值
  27.     MaxandMin(a, l, m, lmax, lmin) ; // 递归计算左半部份

  28.     int rmax ; // 右半部份最大值
  29.     int rmin ; // 右半部份最小值
  30.     MaxandMin(a, m + 1, r, rmax, rmin) ; // 递归计算右半部份

  31.     maxValue = max(lmax, rmax) ; // 总的最大值
  32.     minValue = min(lmin, rmin) ; // 总的最小值
  33. }

2求数组的最大值和次小值
   给定一个含有n个元素的整型数组a,求a中的最大值和次小值。
分析

    思路和上一题类似,同样是用分治法,先求出左边的最大值leftmax和次大值leftsecond,再求出右边的最大值rightmax和次大值rightsecond,然后合并,如何合并呢?分情况考虑。    
    1. 如果leftmax > rightmax,那么可以肯定leftmax是最大值,但次大值不一定是rightmax,但肯定不是rightsecond,只需将leftsecond和rightmax做一次比较即可;
    2. 如果rightmax > leftmax,那么可以肯定的rightmax是最大值,但次大值不一样是leftmax,但肯定不是leftsecond,所以只需将leftmax与rightsecond做一次比较即可;
注意
    这种方法无法处理最大元素有多个的情况,比如3,5,7,7,将返回7,7而不是7,5。感谢网友,从无到有靠他人指出。
代码

  1. // 找出数组的最大值和次大值,a是待查找的数组,left和right是查找区间,max和second存放结果
  2. void MaxandMin(int a[], int left, int right, int&max, int&second)
  3. {
  4.     if(left == right)
  5.     {
  6.         max = a[left] ;
  7.         second = INT_MIN;
  8.     }
  9.     elseif(left +1== right)
  10.     {
  11.         max = a[left] > a[right] ? a[left] : a[right] ;
  12.         second = a[left] < a[right] ? a[left] : a[right] ;
  13.     }
  14.     else
  15.     {
  16.         int mid = left + (right - left) /;

  17.         int leftmax ;
  18.         int leftsecond ;
  19.         MaxandMin(a, left, mid, leftmax, leftsecond) ;

  20.         int rightmax ;
  21.         int rightsecond ;
  22.         MaxandMin(a, mid +1, right, rightmax, rightsecond) ;

  23.         if (leftmax > rightmax)
  24.         {
  25.             max = leftmax ;
  26.             second = leftsecond > rightmax ? leftsecond : rightmax ;
  27.         }
  28.         else
  29.         {
  30.             max = rightmax ;
  31.             second = leftmax < rightsecond ? rightsecond : leftmax ;
  32.         }
  33.     }
  34. }

3求数组中出现次数超过一半的元素
   上海三思软件工程师面试题。给定一个含有n个元素的整型数组a,其中有个元素x出现次数超过n/2,求出这个元素。据说是百度的一道题。
分析

    暂且先不说当前作者的思路,我看到这个问题的时候,想到了如下方法:
    1. 先进行排序,常规的方法就是快速排序,平均时间复杂度为O(nlogn)),然后取第n/2个元素即可,当然,这种方法的前提是存在这个所谓的“主元素”;若不清楚,还是需要验证的;
    2. 由于肯定该数组中含有这么个元素,该题就转换为找中位数了。找中位数的方法线性时间内有两种:
    第一、基于分治法的线性期望时间求中位数,该方法是线性期望时间,类似于快速排序;
    第二、最坏情况下也是线性时间复杂度的方法——“五分中项的中项”划分方法;
    3、分治的思想  若a中存在主元素,则将a分为两部分后,a的主元素也必为两部分中至少一部分主元素,因此可用分治法。
    将元素划分两部分,递归地检查两部分有无主元素。算法如下:
    a. 若a中只含有一个元素,则此元素就是主元素,返回此数;
    b. 将a分为两部分a1和a2(二者元素相等或只差一个),分别递归调用此方法求其主元素m1和m2;
    c. 若m1和m2都存在且相等,则这个是就是a的主元素,返回次数;
    d. 若m1和m2都存在且不相等,则分别检查这两个数是否为a的主元素,若有则返回此数,若无则返回空值;
    e. 若m1和m2都不存在,则a无主元素,返回空值;
    f. 若m1和m2只有一个存在,则检查这个数是否为a的主元素,若是则返回此数,若否就返回空值;

    对于作者给出的这种算法,我在《编程之美》上看到过,即“寻找发帖水王”的题目。
    设置一个当前值和当前值的计数器,初始化当前值为数组首元素,计数器值为1,然后从第二个元素开始遍历整个数组,对于每个被遍历到的值a[i]
    1. 如果a[i] == currentvalue,则计数器加1;
    2. 如果a[i]!= currentvalue,则计数器减一,如果计数器等于0,则更新当前值为a[i],并将计数器值重置为1;
代码
  1. void Find(int a[], int length)
  2. {
  3.     int candidate;
  4.     int i, ntimes;
  5.     i = 0;
  6.     ntimes = 0;
  7.     
  8.     for(= 0; i < length; i++)
  9.     {
  10.         if(ntimes == 0)//计数为0时,读入新的元素,计数加1
  11.         {
  12.             candidate = a[i];
  13.             ntimes = 1;
  14.         }
  15.         else
  16.         {
  17.             if(candidate == a
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值