C++笔试面试(算法题集二)

1>二元查找树变成排序的双向链表

题目:输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。(要求不能创建任何新的结点,只是调整指针的指向)

树结点定义:

Struct BSTreeNode

{

Int m_value;

BSTreeNode *left;

BSTreeNode *right;

};

 

解题思路:

该题涉及树的中序遍历思想(二叉搜索树的中序遍历时一个有序的序列),一般采用递归的方式实现。递归算法(注意边界(即如何退出递归问题),以及何时进入递归)。

 

ANWER

BSTreeNode * TreeToLinkedList(BSTreeNode *root)

{

BSTreeNode *head,*trail;

Helper(head,trail,root);

Return head;

}

 

Void Helper(BSTreeNode &*head,BSTreeNode &*trail,BSTreeNode *root)

{

BSTreeNode *l,*r;

If(root==NULL)

{

    Head=NULL; trail=NULL;

    Return ;

}

Helper(head,l,root->left);

Helper(r,trail,root->right);

If(l!=NULL)

{

    l->right=root;

    root->left=l;

}

Else

{

    Head=root;

}

If(r!=NULL)

{

    r->left=root;

    root->right=r;

}

Else

{

    Trail=root;

}

}

 

2>设计包含min函数的栈

定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数minpush以及pop的时间复杂度都为O(1).

 

Struct MinStackElement{

Int data;

Int min;

};

 

Struct MinStack{

MinStackElement *data;

Int size;

Int top;

};

ANSWER:

 

MinStack MinStackInit(int MaxSize)

{

Minstack stack;

Stack.size=MaxSize;

Stack.top=0;

Stack.data=(MinStackElement*)malloc(sizeof(MinStackElement)*Maxsize);

Return stack;

}

 

Void MinStackFree(MInStrack stack)

{

    Free(stack.data);

}

 

Void MinStackPush(Minstack stack,int d)

{

     If(stack.top==stack.size) ERROR(“out of Memory”);

     MinstackElement *p=stack.data[stack.top];

     P->data=d;

     p->min=(stack.top==0?d:stack.data[top-1]);

     if(p->min>d)

         p->min=d;

     top++;

}

 

Int MinStackPop(MinStack stack)

{

If(stack.top==0)

    ERROR(“error of memory”);

Return stack.data[--stack.top],data;

}

 

Int MinstackMin(Minstack stack)

{

If(stack.top==0)

    ERROR(“out Of memory”);

Return stack.data[stack.top-1].min;

}

 

3>求子数组的最大和

题目:输入一个数组,里面有正数也有负数

数组中连续一个或者多个整数组成一个子数组,每个子数组都有一个和。求所有子数组的最大值,要求时间复杂度O(n)

 

解题思路:经典的动态规划题目,采用动态规划,就可能在o(n)时间内完成。

ANSWER:

 

Int MaxSubArray(int a[],int n)

{

If(n<=0) ERROR(“ERROR array Size”);

Int sum=0;

Int max=-(1<<31);

Int cur=0;

While(cur<n)

{

    Sum+=a[cur++];

    If(sum>max)

    {

        Max=sum;

}

If(sum<0)

    Sum=0;

}

Return max;

}

 

4>在二元树中找出和为某一值的所有路径

题目:输入一个整数和一棵二元树。从树根结点开始往下访问一直到叶子结点所经过的结点形成一条路径。打印出与输入整数相等的所有路径。

 

树结点结构定义:

Struct BinaryTreeNode{

Int m_value;

BinaryTreeNode *left;

BinaryTreeNode *right;

};

 

ANWSER:

 

Void PrintPaths(TreeNode *root,int sum)

{

Int path[MAX_HEIGHT];

Helper(root,sum,path);

}

 

Void Helper(TreeNode *root,int &sum,int &path[],int &cur)

{

Path[cur++]=root.data;

Sum-=root.data;

If(root->left==NULL &&root->right==NULL)

{

    If(sum==0)

        Print(“The road”);

}

Else

{

    If(root->left!=NULL)

        Helper(root->left,sum,path,cur);

    If(root->right!=NULL)

        Helper(root->right,sum,path,cur);

}

Cur--;

Sum+=root.data;

}

 

5>查找最小的K个元素

题目:输入n个整数,输出其中最小的K个。

解题思路:建立一个只能包含K个元素的大顶堆,遍历输入的n个数,若堆中包含的元素的个数小于K个,则加入到堆中。若包含的元素个数已经等于K个。那么喝堆顶的元素比较,若小于堆顶的元素则去掉堆顶元素,该元素入堆,否则直接丢弃。

 

6>给出两个单向链表的头指针,比如h1h2,判断这两个个链表是否相交。

为了简化问题我们假设两个链表均不带环。

问题扩展:

如果链表可能存在环?如果需要求出两个链表相交的第一个结点?

 

ANWSER:

Struct Node{

Int data;

Struct Node *next;

};

 

/*there is no cycle*/

Int isJoinedSimple(Node *h1,Node *h2)

{

While(h1->next!=NULL)

    H1=h1->next;

While(h2->next!=NULL)

    H2=h2->next;

Return h1==h2;

}

 

/*it maybe exits cycle*/

Int isJoined(Node *h1,Node *h2)

{

Node *cycle1=HasCycle(h1);

Node *cycle2=HasCycle(h2);

If(cycle1==NULL && cycle2==NULL)

    isJoinedSimple(h1,h2);                      //无环的情况,采用简单的判断方法

 

if((cycle1==NULL && cycle2!=NULL)||(cycle2==NULL &&cycle1!+NULL))

    return 0;

 

Node *p=cycle1;

While(true)

{

    If(p==cycle2 ||p->next==cycle2)

        Return 1;

    P=p->next->next;

    Cycle1=cycle1->next;

    If(p==cycle1)    return 0;

}

}

 

Node * HasCycle(Node *h)

{

Node *p=h,q=h;

While(p!=NULL && q->next!=NULL)

{

    P=p->next;

    Q=q->next;

    If(p==q)

    {

        Return p;

}

}

Return NULL;

}

 

7>用一种算法逆序一个链表。

ANWSER:

Node *Reverse(Node *head)

{

If(head==NULL) return head;

If(head->next==NULL) return head;

Node *p=Reverse(head->next);

Head->next->next=head;

Head->next=NULL;

Return p;

}

 

Node *ReverseNon(Node *head)

{

If(head==NULL)  return head;

Node *p=head;

Node *pre=NULL;

While(p->next!=NULL)

{

    Node * tmp=p->pNext;

    P->next=pre;

    Pre=p;

    P=tmp;

}

p->next=pre;

return p;

}

 

8>通用字符串匹配算法

ANWSER:

Int isMatch(char *str,char *ptn)

{

If(*ptn==’\0’)  return 1;

If(*ptn==’*’)

{

    Do{

      If(isMatch(str++,ptn+1))

            Return 1;

}while(*str!=’\0’);

}

If(*str==’\0’)  return 0;

If(*str==*ptn ||*ptn==’?’)

   Return isMatch(str+1,ptn+1);

Return 0;

}

 

9>反转一个字符串

ANWSER:

Void  ReverseString(char *str,int n)

{

Char *p=str+n-1;

While(str<p)

{

    Char ch=*str;

    *str=*p

    *p=ch;

    Str++; p--;

}

}

 

10>比较两个字符串,用o(n)时间和恒量空间。

ANWSER

Int strcmp(char *p1,char *p2)

{

While(*p1!=’\0’ && *p2!=’\0’ &&*p1==*p2)

{

    P1++;p2++;

}

If(*p1==’\0’ && *p2==’\0’)  return 0;

If(*p1==’\0’)  return -1;

If(*p2==’\0’)  return 1;

Return (*p1-*p2);

}

 

11>判断整数序列是不是二元查找树的后序遍历结果

题目:输入一个整数数组,判断该数组是不是某二元查找树的后续遍历结果。

ANWSER:

Int isPostorderResult(int a[],int n)

{

    Return helper(a,0,n-1);

}

 

Int helper(int a[],int s,int e)

{

If(e==s)  return 1;

Int i=e-1;

While(a[e]<a[i] && i>=s) i--;

If(!helper(a,i+1,e-1))

    Return 0;

Return helper(a,s,i);

}

 

12>求二叉树中结点的最大距离

ANWSER:

Int maxDistance(Node *root)

{

Int depth;

Return helper(root,depth);

}

 

Int helper(Node* root,int &depth)

{

If(root==NULL)

{

    Depth=0;  return 0;

}

Int ld,rd;

Int maxleft=helper(root->left,ld);

Int maxright=helper(root->right,rd);

Depth=max(ld,rd)+1;

Return max(maxleft,max(maxright,ld+rd));

}

 

13>输出一个单向链表中倒数第K个结点。

ANWSER:

Struct ListNode{

Int m_value;

ListNode *m_pNext;

};

 

ListNode *LastK(ListNode *head,int k)

{

If(k<0)  exit(0);

Node *p=head,*pk=head;

For(;k>0;k--)

{

    If(pk->next!=NULL)

       Pk=pk->next;

    Else

        Return NULL;

}

While(pK->next!=NULL)

{

    P=p->next;

    pK=pK->next;

}

Return p;

}

 

14->输入一个已经按照升序排序过的数组和一个数字,在数组中查找两个数,使他们的和正好是输入的那个数字。输出1对即可以。

ANSWER:

Void Find2Number(int a[],int n,int dest)

{

Int *start=a,*end=a+n-1;

Int sum=*start+*end;

While(sum!=dest && start<end)

{

If(sum<dest) 

{

    Sum-=*start;

    Sum+=*++start;

}

Else

{

    Sum-=*end;

    Sum+=*--end;

}
    }

If(sum==dest) cout<<*start<<” ”<<*end<<endl;

}

 

15->输入一棵二元查找树,将该树转换位它的镜像

ANSWER

Struct BSTreeNode{

Int m_value;

BSTreeNode *left;

BSTreeNode *right;

};

Void Mirror(BSTreeNode *root)

{

If(root==NULL)  return;

Swap(root->left,root->right);

Mirror(root->left);

Mirror(root->left);

}

 

16->输入一个二元树,从上往下打印每个结点,同一层按照从左往右的顺序打印。

ANSWER:

引入队列可以很简单的就解决这一道题。

 

17->在字符串中找到第一次值出现一次的字符。

ANSWER:

Char FirstSingle(char *str)

{

Int c[255];

Memset(c,0,sizeof(a));

Char *p=str;

While(*p!=’\0’)

{

    c[*p]++;

    p++;

}

P=str;

While(*p!=’\0’)

{

    If(c[*p]==1)

        Return *p;

}

Return ‘\0’;

}

 

18->n 个数字(0,1,….,n-1)形成一个圆圈,从数字0开始,每次从这个圈中删除第m个数字,当一个数字删除后,从被删除数字的下一个继续删除第m个数字。求出这个圆圈中剩下的最后一个数字。

ANSWER:

答案比较简单,但是整个过程比较难理解。

Int joseph(int n,int m)

{

Int fn=0;

For(int i=2;i<=n;i++)

    Fn=(fn+m)%i;

Return fn;

}

 

19->输入一个表示整数的字符串,把字符串转换成整数并输出

ANSWER:

Int atoi(char *str)

{

Int  neg=0;

Char *p=str;

If(*p==’-’)

{

    P++;

    Neg=1;

}else if(*p==’+’)

{

    P++;

}

Int result=0;

While(*p!=’\0’)

{

    If(*p>=’0’ && *p<=’9’)

{

    Num=num*10+(*p-‘0’);

}

Else

{

    ERROR(“illegal number”);

}

P++;

}

Return num;

}

 

 

20->输入两个整数n,m,从数列1,2,3……,n中随意取出几个数,使其和等于m。要求求出其中所有的可能组合。

ANSWER:

Void FindCombination(int n,int m)

{

If(n>m) findCombination(m,m);

Int aux[n];

Memset(aux,0,sizeof(aux));

Helper(m,0,aux,n);

}

 

Void Helper(int dest,int index,int aux[],int n)

{

If(dest==0)

{cout<<aux<<endl;}

If(dest<0 || index==n) return;

Helper(dest,index+1,aux,n);

Aux[index]=1;

Helper(dest-index-1,index+1,aux,n);

Aux[index]=0;

}

 

21->合并一个链表

ANSWER:

Node *merge(Node *h1,Node *h2)

{

If(h1==NULL) return h2;

If(h2==NULL) return h1;

 

Node* head;

If(h1->data>h2->data)

{

     Head=h2;h2=h2->next;

}

Else

{

    Head=h1;h1=h1->next;

}

Node *p=head;

While(h1!=NULL &&h2!=NULL)

{

    if(h1->data>h2->data)

    {

        p->next=h2;h2=h2->next;p=p->next;

}

Else

{

    p->next=h1;h1=h1->next;p=p->next;

}

}

If(h1!=NULL) p->next=h1;

If(h2!=NULL) p->next=h2;

Return head;

}

 

22->写一个函数,实现在字符串中找出连续最长的数字串,并把这个串的长度返回。

ANSWER:  

Int continumax(char* outputstr,char* inputstr)

{

Int len=0;

Char* pstart=NULL;

Int max=0;

While(true)

{

    If(*inputstr>=’0’ &&*inputstr<=’9’)

        Len++;

    Else

    {

         If(len<max)

             Pstart=inputstr-len;

         Len=0;

}

If(*inputstr++=’\0’)  break;

}

For(int i=0;i<len;i++)

{

    *outputstr++=pstart++;

    *outputstr=’\0’;

    Return max;

}

}

 

23->整数二进制表示中1的个数

ANWSER:

Int countof1(int n)

{

Int c=0;

While(n!=0)

{

    N=n&(n-1);

    C++;

}

Return c;

}

 

29->栈的pushpop序列

ANWSER:

Int isPopSeries(int push[],int pop[],int n)

{

Stack<int> st;

Int i1=0,i2=0;

St.push(push[i1]);

While(i2<n)

{

    While(st.empty()||st.top()!=pop[i2])

    {

        If(i1<n)

            St.push(push[++i1]);

        Else

            Return 0;

        While(!=st.empty()&&st.top()==pop[i2])

{

    St.pop();  i2++;

}

}

}

Return 1;

}

 

30->求一个数组的最长递减子序列。比如{94325432}的最长递减子序列为{95432}

ANSWER:

Int [] FindDecreasing(int[] a)

{

Int *Ds=new int[a.size()]();

Int dsl=0;

Int lastIndex=0;

For(int i=0;i<a.length;i++)

{

    Int s=0,t=dsl-1;

    While(s<=t)

    {

        Int m=s+(s-t)/2;

        If(Ds[m]<a[i])

            T=m-1;

        Else

            S=m+1;

    Ds[s]=a[i];

    If(s>dsl){dsl=s+1,lastIndex=i}

}

}

For(int i=lastIndex,j=dsl-1;i>=0&&j>=0;i--)

{

   If(a[i]==Ds[j])  j--;

   Else if(a[i]<Ds[j] &&a[i]>Ds[j+1])

       Ds[j--]=a[i];

}

Return copy(Ds,0,dsl);

}

 

31->一个整数数组,长度为n,将其分为m份,使各分的和相等,求m的最大值。

例如{3,2436}可以分成{32、、436}m=1

{36}{243}m=2  {33}{24}{6}m=3

ANWSER:

Int maxShares(int a[],int n)

{

   Int sum=0;

   For(int i=0;i<n;i++) sum+=a[i];

   For(int m=n;m>=2;m--)

   {

       If(sum%m!=0) continue;

       Int *aux=new int[n]();

       If(TestShares(a,n,m,sum/m,aux,1))   return m;

}

Return 1;

}

 

Int TestShares(int a[],int n,int m,int Dest,int aux[],int id)

{

If(Dest==0)

{

   Id++;  if(id==m+1) return 1;

}

For(int i=0;i<n;i++)

{

   If(aux[i]!=0) continue;

    Aux[i]=id;

    If(testShares(a,,n,m,Dest-a[i],aux,id))

        Return 1;

    Aux[i]=0;

}

}

 

32->旋转数组的value值查找问题

ANWSER:

Int ShiftedBinarySearch(int a[],int k)

{

    Return Helper(a,k,0,n-1);

}

Int Helper(int a[],int k,int s,int t)

{

If(s>t)  return -1;

Int m=s+(s-t)/2;

If(a[m]==k) return m;

Else if(a[s]>=k &&k>a[m])  return Helper(a,k,s,m-1);

Else return helper(a,k,m+1,t);

}

 

33->调整数组顺序是奇数位于偶数的前面

ANWSER

Void partition(int a[],int n)

{

Int i=0;

Int j=n-1;

While(i<j)

{

    While(i<j &&a[i]&1==0) i++;

    While(i<j &&a[j]&1==1) j--;

    Swap(a[i],a[j]);

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值