几道经典笔试题目

来源:互联网 发布:人工智能瓶颈阶段 编辑:程序博客网 时间:2024/04/28 19:38

1.递归合并有序链表

2.寻找二叉树中两个节点的最近的公共祖先

3.进制算法转换

4.大小写转换

5.求两同长数组的中位数问题

6.求数组的第k大的数字

7. 最接近S的中位数的k个数

1.递归合并有序链表

Node* mergAction(Node* head1,Node *head2){   Node *p=NULL;   if(head1==NULL&&head2==NULL)       return p;   else if(head1==NULL)       return head2;   else if(head2==NULL)       return head1;   else   {        if(head1->data < head2->data)        {            p = head1;            p->next = mergAction(head1->next,head2);        }        else        {           p = head2;           p->next = mergAction(head1,head2->next);        }        return p;   }}

2.寻找二叉树中两个节点的最近的公共祖先

class Node{   Node * left;   Node * right;   Node * parent;};/*查找p,q的最近公共祖先并将其返回。*/Node * NearestCommonAncestor(Node * p,Node * q);

Node * NearestCommonAncestor(Node * root,Node * p,Node * q){Node * temp;         while(p!=NULL){p=p->parent;temp=q;while(temp!=NULL){if(p==temp->parent)return p;temp=temp->parent;}}}

解法2:算法思想:如果一个节点的左子树包含p,q中的一个节点,右子树包含另一个,则这个节点就是p,q的最近公共祖先。

/*查找a,b的最近公共祖先,root为根节点,out为最近公共祖先的指针地址*/int FindNCA(Node* root, Node* a, Node* b, Node** out) { if( root == null ) { return 0; }if( root == a || root == b ){    return 1;}int iLeft = FindNCA(root->left, a, b, out);if( iLeft == 2 ){    return 2;}int iRight = FindNCA(root->right, a, b, out);if( iRight == 2 ){    return 2;}if( iLeft + iRight == 2 ){   *out = root;}return iLeft + iRight;}void main() { Node* root = ...; Node* a = ...; Node* b = ...; Node* out = null; int i = FindNCA(root, a, b, &out); if( i == 2 ) { printf("Result pointer is %p", out); } else { printf("Not find pointer"); } }


3.进制算法转换

编程实现将十进制的整数转化成任意进制的整数,用户输入

一个十进制数R和想要转化的进制数X,程序输出转换后的X进制的整数。

算法思想:将十进制数R与进制X取模,即R%X的值作为X进制整数的倒数第一位,

然后使R等于R/X,再取R%X的值作为X进制整数的倒数第二位......依次类推,直

到最后R/X=0为止。

#include <iostream>#include <string>using namespace std;

 

/*将一个整型数字转化成字符型数字,例如 8->'8',12->'c'*/void numToChar(char &num){

 /*num是0到9之间的数字*/ if(num<=9&&num>=0) {  num+=48; }

 

 /*num是10到15之间的数字*/ else {  switch(num)  {  case 10:num='A';  case 11:num='B';  case 12:num='C';  case 13:num='D';  case 14:num='E';  case 15:num='F';  } }}

 

/*进制转化函数——r表示需要被转化的十进制数,x表示进制(1<x<17)*/void decimalTransmit(int r,int x){ string result;//保存x进制数 char temp; while(r>0) {  temp=r%x;        numToChar(temp);  result+=temp;  r=r/x; }  /*输出转化后的x进制整数*/ for(int i=result.size()-1;i>=0;i--)  cout<<result[i]; cout<<endl;}

 

int main(){ int R,X; cout<<"请输入一个十进制数和要转化的进制(用空格作为间隔符):"; cin>>R>>X; decimalTransmit(R,X); return 0;}

还有一个mton的算法,很漂亮,但是遗憾的是只支持1~10进制的转换。

void m2n(int m, char* mNum, int n, char* nNum) {int i = 0;char c, *p = nNum;//这是一个考察地方,是否能用最少乘法次数。while (*mNum != '\0')i = i*m + *mNum++ - '0';//辗转取余while (i) {*p++ = i % n + '0';i /= n;}*p-- = '\0';//逆置余数序列while (p > nNum) {c = *p;*p-- = *nNum;*nNum++ = c;}}


4.大小写转换

#define to_uppercase(ch) ((ch) - 'a' + 'A')#define to_lowercase(ch) ((ch) - 'A' + 'a')

以后记不住,记住带入特殊值作检验:

‘a’->‘A’    ‘a’ - ‘a’ + ‘A’

‘A’->‘a’    ‘A’ - 'A'  + 'a'

貌似这么简答我都在考场上想了很久,足见状态之差


5.求两同长数组的中位数问题

中位数问题:设X[0:n-1]和Y[0:n-1]为两个数组,每个数组中含有N个 已经排好序的数。试设计一个O(logn)时间算法,找出X和Y的2N个数的中位数。

     解决问题的核心:找出将大问题分割成较小规模的相同问题的切割点,并递归定义大问题与子问题之间的关系。
     确定切割点:对于两个数组,我们可以从他们中分别选取出一个中位数,称为x,y,并将两个数组的左右边界称之为aLeft,aRight,bLeft,bRight。对比两个中位数,如果X数组中的中位数大于Y数组中的中位数,且X数组中的元素个数为偶数个,则X数组被切割为X[aLeft,x+1],Y被切割为Y[y,bRight],如果X数组的元素个数不为偶数个的话,则直接将X切割为X[aLeft,x]。如果X数组的中位数小于Y数组的中位数,取值情况刚好相反。
     递归关系:根据上面所述,对于原问题X[aLeft , aRight], Y[bLeft, bRight]。假设切割后的子问题为X[aLeft, x+1],Y[y,bRight]。则求解X[aLeft , aRight], Y[bLeft, bRight]问题的中位数,归结于求解子问题X[aLeft, x+1],Y[y,bRight]的中位数。
     递归结束条件:当切割后得到的子问题的两个数组的长度都为2位时,整个递归结束。
实际问题的输入:
第一行: n,为x和y数组的元素个数
第二行: x数组的n个数,用空格分隔

第三行: y数组的n个数,用空格分隔

算法的输出:

中位数两个,用空格分隔
#include <stdio.h>#include <stdlib.h>int main(){    //两个数组    int len = 0;    //获取数组的长度    scanf("%d", &len);    //动态分配数组    int * a;    int * b;    a = (int *)malloc(sizeof(int) * len);    b = (int *)malloc(sizeof(int) * len);    //获取每个数组的元素    for(int i=0; i < len; i++)    {        scanf("%d", &a[i]);    }    for(int j=0; j < len; j++)    {        scanf("%d", &b[j]);    }    //两个数组的左右端点的坐标    int aLeft = 0;    int aRight = len - 1;    int bLeft = 0;    int bRight = len - 1;    //两数组中间坐标    int aMid = 0;    int bMid = 0;    //迭代循环    while(true)    {        //printf("a left is %d right is %d, and b left is %d right is %d.\n", aLeft, aRight, bLeft, bRight);        //  如果两个数组都只剩下两个元素,则中位数一定在其中        if( (aRight - aLeft) == 1 && (bRight - bLeft) == 1)        {            //  输出第一行的最大一个值            printf("%d ", (a[aLeft]>=b[bLeft])?a[aLeft]:b[bLeft]);            //  输出第一行的最小一个值            printf("%d\n", (a[aRight]<=b[bRight])?a[aRight]:b[bRight]);            //  结束循环            break;        }        else        {            //  求解各个数组的中值            aMid = (int)((aLeft + aRight)/2);            bMid = (int)((bLeft + bRight)/2);            //  如果A中值小于B中值            if(a[aMid] < b[bMid])            {                //  如果B中现存的数列是偶数个,右边值加一                if((bLeft + bRight + 1) % 2 == 0) {                    aLeft = aMid;                    bRight = bMid + 1;                }               else {                    aLeft = aMid;                    bRight = bMid;                }            }            //  如果B中值小于A中值            else            {                //  如果A中现存的数列是偶数个,右边值加一                if((aLeft + aRight + 1) % 2 == 0) {                    aRight = aMid + 1;                    bLeft = bMid;               }                else {                    aRight = aMid;                   bLeft = bMid;               }              }        }    }    return 0;}

6.求数组的第k大的数字:

      太经典了,经常面试问到。具体参考《算法导论》
  
#include <cstdlib>#include <iostream>/** *求一个数组中的第k大数 *基本思想: *以最后一个元素x为轴,把数组分为两部分Sa和Sb。Sa中的元素大于等于X,Sb中元素小于X。这时有两种情况: *1.Sa中元素的个数小于k,则Sb中的第k-|Sa|个元素即为第k大数; *2.Sa中元素的个数大于等于k,则返回Sa中的第k大数。 *时间复杂度近似为O(n)  */using namespace std;void exchange(int &a,int &b){    int temp;    temp=a;    a=b;    b=temp;}//快排的partition函数 int partition(int *a,int l,int r){    int i=l-1,j=l;    int x=a[r];    int temp;        for(j=l;j<r;j++)    {        if(a[j]>=x) //把比x大的数往前放             {            exchange(a[j],a[i+1]);            i++;                }            }    exchange(a[r],a[i+1]);    return i+1;        }int k_element(int *a,int l,int r, int k){    if(l>=r)        return a[l];    int q=partition(a,l,r);    if(q==k-1)        return a[q];       else if(q>=k)        return k_element(a,l,q-1,k); //Sa中元素个数大于等于k       else        return k_element(a,q+1,r,k-(q+1)); //Sa中元素个数小于k    }int main(int argc, char *argv[]){    int a[100];    int length;        cin>>length;        for(int i=0;i<length;i++)        cin>>a[i];    cout<<k_element(a,0,length-1,4)<<endl;        system("PAUSE");    return EXIT_SUCCESS;}

7. 最接近S的中位数的k个数
      问题描述:
      给定由n个互补相同的数组成的集合S以及正整数k<=n,试设计一个O(n)时间算法找出S中最接近S的中位数的k个数。
算法分析:
     首先,通过select算法得到这个数组的中位数,然后最这个集合中的每一个数都减去这个中位数然后取abs();最后在第二步得到的集合中,取第k小的数,再取小于第k小的数的k-1个数,他们原来的数,就是要求的k个数。PS:此算法有缺陷,要求保证绝对值数组中无重复,否则无法线性。


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 主板没有m.2接口怎么办 点痣留下了疤怎么办 危险三角区长痘痘怎么办 挤了危险三角区怎么办 三角区长痘挤了怎么办 三角区发红长痘怎么办 激光祛斑碰水了怎么办 激光打痣留下坑怎么办 点痣之后留下坑怎么办 去痣留下的红印怎么办 激光点痦子留疤怎么办 激光点痣的疤痕怎么办 做完眉毛碰水了怎么办 脸上疤掉了有坑怎么办 结痂不小心抠掉怎么办 脸上肉松弛怎么办19岁 点痣留下来的疤怎么办 激光祛斑的红印怎么办 脸上疤掉了红印怎么办 痘痘发炎了红肿怎么办 脸上的斑越来越多了怎么办 点痣留下的疤痕怎么办 额头又高又大怎么办 脸太长额头太高怎么办 动车因台风停运怎么办 爸妈50了要离婚怎么办 鸿利彩票黑了钱怎么办 忘了锁屏图案怎么办 黄金被水银沾上怎么办 被股东了我该怎么办 异地恋没话题聊怎么办 谈了半年分手了怎么办 博士6年没毕业怎么办 发现孩子早恋家长应该怎么办 异地恋想嘿嘿嘿怎么办 妈妈溜冰溜大了怎么办 皮鞋被雨水泡了怎么办 老婆提出离婚我不想离怎么办 极度缺爱的人怎么办 生二胎住院大宝怎么办 爸妈偏心我该怎么办