精选面试算法的实现之一

来源:互联网 发布:凉山新闻网络电视频道 编辑:程序博客网 时间:2024/06/05 10:17

注明:本文的题目来自http://blog.csdn.net/v_july_v/article/details/5934051 感谢作者的搜集。

本人在此用C语言进行编程实现,有些题目的实现跟原贴有些不同,提供另一种思路。

水平有限,读者仅供参考。


1.把二元查找树转变成排序的双向链表
 题目:
输入一棵二元查找树,将该二元查找树转换成一个排序的双向链表。
要求不能创建任何新的结点,只调整指针的指向。
   
  10
  / /
 6 14
 / / / /
4 8 12 16
   
 转换成双向链表
4=6=8=10=12=14=16。

#include <stdio.h>#include <assert.h>#include <stdlib.h>typedef struct _node{int val;struct _node *left;struct _node *right;}node;typedef struct _Stack{node *p;struct _Stack *next;}Stack;static Stack *top=NULL;void push(node *n){Stack *tmp=(Stack *)malloc(sizeof(Stack));tmp->p=n;tmp->next=top;top=tmp;}node *pop(){if(top==NULL) {printf("the stack is empty ");return NULL;}Stack *tmp=top;top=top->next;node *mynode=tmp->p;free(tmp);return mynode;}/* add node to a exist tree */int addnode(int val,node *root){assert(root!=NULL);if(root->val==val){printf("exist the val\n");return -1;}else if (root->val>val){if(root->left==NULL){node *tmp=(node *)malloc(sizeof(node));tmp->val=val;tmp->left=tmp->right=NULL;root->left=tmp;return 1;}else{addnode(val,root->left);}}else{if(root->right==NULL){node *tmp=(node *)malloc(sizeof(node));tmp->val=val;tmp->left=tmp->right=NULL;root->right=tmp;return 1;}else{addnode(val,root->right);}}}/* for test ,traverse the link by inorder */void midwalk(node *root){if(root!=NULL){midwalk(root->left);printf("%d\t",root->val);midwalk(root->right);}}/* change the tree to link list */node *changeToLink(node *root){node *mynode=root;node *head=NULL;node *tail=NULL;while((mynode!=NULL)||(top!=NULL)){while(mynode!=NULL){push(mynode);mynode=mynode->left;}if(top!=NULL){node *tmp=pop();if(head==NULL){head=tmp;tail=tmp;}else{tail->right=tmp;tmp->left=tail;tail=tmp;}//printf("%d\t",tmp->val);mynode=tmp->right;}}return head;}/* print the link list */void printLink(node *p){while(p!=NULL){printf("%d\t",p->val);p=p->right;}}int main(){node *tree=(node *)malloc(sizeof(node));tree->val=10;addnode(6,tree);addnode(14,tree);addnode(4,tree);addnode(8,tree);addnode(12,tree);addnode(16,tree);node *test=changeToLink(tree);printLink(test);printf("\n");return 0;}


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

#include <stdio.h>#include <assert.h>#include <stdlib.h>typedef struct _Ele{int val;struct _Ele *next;struct _Ele *currentMin;}Ele;struct Stack{Ele *top;};struct Stack *initStack(){struct Stack *s;s=(struct Stack *)malloc(sizeof(struct Stack));s->top=NULL;return s;}int empty(struct Stack *s){if(s->top==NULL){return 1;}else{return 0;}}void push(struct Stack *s,int val){/* init the new node */Ele *e=(Ele *)malloc(sizeof(Ele));e->val=val;e->next=NULL;e->currentMin=e;if(s->top!=NULL){int min=s->top->currentMin->val;if(val<min){e->currentMin=e;}else{e->currentMin=s->top->currentMin;}}e->next=s->top;s->top=e;}int min(struct Stack *s){if(s==NULL){printf("the stack is empty\n");exit(-1);}return s->top->currentMin->val;}int pop(struct Stack *s){if(s->top==NULL){printf("the stack is empty\n");exit(-1);}Ele *newtop=s->top->next;int retval=s->top->val;free(s->top);s->top=newtop;return retval;}int main(){struct Stack *mysta=NULL;mysta=initStack();push(mysta,3);push(mysta,2);push(mysta,4);push(mysta,5);push(mysta,1);push(mysta,9);int p=pop(mysta);printf("pop out %d\n",p);int d=min(mysta);printf("the min is %d\n",d);int p2=pop(mysta);printf("pop out %d\n",p2);int d2=min(mysta);printf("the new min is %d\n",d2);return  0;}


3.求子数组的最大和
题目:
输入一个整形数组,数组里有正数也有负数。
数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和。
求所有子数组的和的最大值。要求时间复杂度为O(n)。

例如输入的数组为1, -2, 3, 10, -4, 7, 2, -5,和最大的子数组为3, 10, -4, 7, 2,
因此输出为该子数组的和18。

(最大子段和问题)

#include <stdio.h>#include <assert.h>#include <stdlib.h>int maxSeq(int *array,int len){int max=0;int b=0;int i;for(i=0;i<len;i++){if(b>0){b+=array[i];}else{b=array[i];}if(b>max)max=b;}return max;}int main(){int values[]={1,-2,3,10,-4,7,2,-5};int res=maxSeq(values,8);printf("max is %d\n",res);return 0;}

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

题目:输入一个整数和一棵二元树。
从树的根结点开始往下访问一直到叶结点所经过的所有结点形成一条路径。
打印出和与输入整数相等的所有路径。
例如 输入整数22和如下二元树
  10   
  / /   
  5 12   
  / /   
  4 7
则打印出两条路径:10, 12和10, 5, 7。

二元树节点的数据结构定义为:

struct BinaryTreeNode // a node in the binary tree
{
int m_nValue; // value of node
BinaryTreeNode *m_pLeft; // left child of node
BinaryTreeNode *m_pRight; // right child of node

};

思路:这里给出的节点定义已经定义好了,试想,如果我们在每个节点处增加一个数据项,这样的话,每次遍历这棵树,如果遇到叶子结点,就顺着父亲结点一直搜索到根结点,如果满足指定的和,则打印之。

这是最为直观的解题思路了,是吧?你可能会说题目给出的结点就这样了,但我也可以说我再根据输入的树自定义一棵副本树呢,呵呵。这是题目问题,在没有限制的情况下,添加一个指向父亲结点的指针就搞定了。

具体代码就省略啦

5.查找最小的k个元素
题目:输入n个整数,输出其中最小的k个。
例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4。

#include <stdio.h>#include <assert.h>#include <stdlib.h>void findMink(int *a,int len,int k){assert(k<len);int i;for(i=0;i<k;i++){int j;for(j=len-1;j>i;j--){if(a[j]<a[j-1]){int tmp=a[j];a[j]=a[j-1];a[j-1]=tmp;}}}for(i=0;i<k;i++){printf("%d\n",a[i]);}}int main(){int val[]={8,7,6,5,4,3,2,1};findMink(val,8,4);return 0;}


第8题

非算法题目,略,有兴趣读者参考原贴。

第9题

判断整数序列是不是二元查找树的后序遍历结果
题目:输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果。
如果是返回true,否则返回false。
例如输入5、7、6、9、11、10、8,由于这一整数序列是如下树的后序遍历结果:
  8
  / /
  6 10
  / / / /
  5 7 9 11
因此返回true。
如果输入7、4、6、5,没有哪棵树的后序遍历的结果是这个序列,因此返回false。


(下面的解法是参考原作者给出的答案,对原作者的解法表示赞)

#include <stdio.h>#include <assert.h>int assertTree(int *val,int len){if(val==NULL||len<=0) return 0;int root=val[len-1];int i=0;for(;i<len-1;i++){if(val[i]>root)break;}int j=i;for(;j<len-1;++j){if(val[j]<root)return 0;}int left=1;if(i>0)left=assertTree(val,i);int right=1;if(i<len-1)right=assertTree(val+i,len-i-1);return (left&&right);}int main(){int val[]={5,7,6,9,11,10,8};int res=assertTree(val,7);printf("%d\n",res);return 0;}

2.设计包含min函数的栈。
定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。

要求函数min、push以及pop的时间复杂度都是O(1)。

#include <stdio.h>#include <assert.h>#include <stdlib.h>typedef struct _Ele{int val;struct _Ele *next;struct _Ele *currentMin;}Ele;struct Stack{Ele *top;};struct Stack *initStack(){struct Stack *s;s=(struct Stack *)malloc(sizeof(struct Stack));s->top=NULL;return s;}int empty(struct Stack *s){if(s->top==NULL){return 1;}else{return 0;}}void push(struct Stack *s,int val){/* init the new node */Ele *e=(Ele *)malloc(sizeof(Ele));e->val=val;e->next=NULL;e->currentMin=e;if(s->top!=NULL){int min=s->top->currentMin->val;if(val<min){e->currentMin=e;}else{e->currentMin=s->top->currentMin;}}e->next=s->top;s->top=e;}int min(struct Stack *s){if(s==NULL){printf("the stack is empty\n");exit(-1);}return s->top->currentMin->val;}int pop(struct Stack *s){if(s->top==NULL){printf("the stack is empty\n");exit(-1);}Ele *newtop=s->top->next;int retval=s->top->val;free(s->top);s->top=newtop;return retval;}int main(){struct Stack *mysta=NULL;mysta=initStack();push(mysta,3);push(mysta,2);push(mysta,4);push(mysta,5);push(mysta,1);push(mysta,9);int p=pop(mysta);printf("pop out %d\n",p);int d=min(mysta);printf("the min is %d\n",d);int p2=pop(mysta);printf("pop out %d\n",p2);int d2=min(mysta);printf("the new min is %d\n",d2);return  0;}



第10题
翻转句子中单词的顺序。
题目:输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。句子中单词以空格符隔开。
为简单起见,标点符号和普通字母一样处理。
例如输入“I am a student.”,则输出“student. a am I”。


#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <string.h>void swap(char *first,char *last){assert(first!=NULL&&last!=NULL);char tmp;while(first<last){tmp=*first;*first=*last;*last=tmp;first++;last--;}}void reverseWord(char *str,int len){assert(str!=NULL&&len>0);char *head=str,*tail=str+len-1;char tmp;while(head<tail){tmp=*head;*head=*tail;*tail=tmp;head++;tail--;}head=str;tail=str;for(tail=str;*tail!='\0';tail++){if(*tail==' '){tail--;swap(head,tail);tail++;head=tail+1;}}if(*tail=='\0'){tail--;swap(head,tail);}return ;}int main(){char str[]="I am a student.";printf("%s\n",str);reverseWord(str,strlen(str));printf("%s\n",str);return 0;}


第11题
求二叉树中节点的最大距离...

如果我们把二叉树看成一个图,
父子节点之间的连线看成是双向的,
我们姑且定义"距离"为两节点之间边的个数。
写一个程序,
求一棵二叉树中相距最远的两个节点之间的距离。


这个本人暂时没想到什么比较好的办法,有兴趣的读者自己参考http://blog.csdn.net/v_july_v/article/details/5990750

第12题
题目:求1+2+…+n,
要求不能使用乘除法、for、while、if、else、switch、case等关键字以及条件判断语句(A?B:C)。

这个题目俺想了好久,原作者给的答案用C++的虚函数去实现的好像,比较复杂。

俺这里给出一个简单实现版。

#include <stdio.h>#include <stdlib.h>int add1ton(int n,int *res){*res=1;int ret;int *mid=(int *)malloc(sizeof(int));return (n-1==0)||(add1ton(n-1,mid),*res=*mid+n);}int main(){int *p=(int *)malloc(sizeof(int));add1ton(100,p);printf("result is %d\n",*p);return 0;}


第13题:
题目:输入一个单向链表,输出该链表中倒数第k个结点。链表的倒数第0个结点为链表的尾指针。
链表结点定义如下:   
struct ListNode
{
  int m_nKey;
  ListNode* m_pNext;
};

#include <stdio.h>#include <stdlib.h>#include <assert.h>typedef struct _linknode{int key;struct _linknode *next;}linknode;void locateRK(linknode *first,int k){assert(k>=0&&first!=NULL);linknode *p=first;linknode *prek=p;while(k>0){assert(p!=NULL);p=p->next;k--;}while(p!=NULL){p=p->next;prek=prek->next;}printf("the last k val is %c\n",prek->key);}int main(){char c;linknode *head=NULL;linknode *tail=head;while(c=getchar()){if(c=='#') break;linknode *p=(linknode *)malloc(sizeof(linknode));p->key=c;p->next=NULL;if(head==NULL){head=p;tail=p;}else{tail->next=p;tail=p;}}locateRK(head,3);}



第14题:题目:输入一个数组和一个数字,在数组中查找两个数,使得它们的和正好是输入的那个数字。要求时间复杂度是O(n)。如果有多对数字的和等于输入的数字,输出任意一对即可。

#include <stdio.h>#include <assert.h>#include <stdlib.h>#include <string.h>/** *in a given array,to find two number ,the sum of which is sum * assume the max of sum is 100 * */typedef unsigned int uint;void findAddElem(uint *num,int len,uint sum){int MAX=100;int MASK=0x01;int bytelen=8;char *bitmap=(char *)malloc(1+MAX/bytelen);memset(bitmap,0,1+MAX/bytelen);int i;/* to prepare ,make the bitmap */for(i=0;i<len;i++){uint val=num[i];uint outeroffset=(int)(val/bytelen);uint inneroffset=val%bytelen;bitmap[outeroffset]|=MASK<<inneroffset;}/*this time find the needed bit is set or not */for(i=0;i<len;i++){uint val=num[i];uint left=sum-val;uint outeroffset=(int)(left/bytelen);uint inneroffset=left%bytelen;uint flag=bitmap[outeroffset]&(MASK<<inneroffset);if(flag!=0){printf("%d+%d=%d\n",val,left,sum);break;}}free(bitmap);}int main(){uint numbers[5]={20,35,23,45,27};findAddElem(numbers,5,50);return 0;}


第15题:
题目:输入一颗二元查找树,将该树转换为它的镜像,
即在转换后的二元查找树中,左子树的结点都大于右子树的结点。
用递归和循环两种方法完成树的镜像转换。   

第16题:
题目(微软):
输入一颗二元树,从上往下按层打印树的每个结点,同一层中按照从左往右的顺序打印。   
例如输入

              a

      b               e

c         d       f          g

将输出abecdfg

15,16 类似,在一起实现了

#include <stdio.h>#include <stdlib.h>#include <assert.h>struct _node {char val;struct _node *left;struct _node *right;};typedef struct _node node;typedef struct _stackE{struct _stackE *next;node *data;}stackE;static stackE *head=NULL;static stackE *tail=NULL;static void enqueue(node *p){/* ignored the overflow */stackE *ele=(stackE *)malloc(sizeof(stackE));ele->data=p;ele->next=NULL;if(head==NULL||tail==NULL){head=tail=ele;}else{assert(tail!=NULL);tail->next=ele;tail=ele;}}static node *dequeue(){node *ret=NULL;if(head==NULL||tail==NULL){return ret;}stackE *p=head;ret=p->data;head=p->next;if(head==NULL){tail=NULL;}free(p);return ret;}static int isEmpty(){if(head==NULL||tail==NULL){return 1;}else{return 0;}}void levelWalk(node *tree){if(tree==NULL){printf("the tree is null\n");return ;}else{enqueue(tree);while(!isEmpty()){node *p=dequeue();printf("%c\t",p->val);if(p->left!=NULL){enqueue(p->left);}if(p->right!=NULL){enqueue(p->right);}}}}void formMirror(node *tree){if(tree==NULL){return;}else{enqueue(tree);while(!isEmpty()){node *p=dequeue();if(p->left!=NULL){enqueue(p->left);}if(p->right!=NULL){enqueue(p->right);}node *tmp=p->left;p->left=p->right;p->right=tmp;}}}/**  * form mirror tree,recursive algorithm  * */void makeMirror(node *tree){if(tree==NULL){return;}else{if(tree->left!=NULL){makeMirror(tree->left);}if(tree->right!=NULL){makeMirror(tree->right);}node *tmp=tree->left;tree->left=tree->right;tree->right=tmp;}}/* * to create a tree ,sample input string:abc##d##ef##g## */node *createTree(){char val;val=getchar();if(val=='#'){return NULL;}else{node *root=(node *)malloc(sizeof(node));root->val=val;root->left=createTree();root->right=createTree();return root;}}void midWalk(node *p){if(p!=NULL){midWalk(p->left);printf("%c\t",p->val);midWalk(p->right);}}int main(){node *tree=createTree();levelWalk(tree);printf("\n");makeMirror(tree);levelWalk(tree);printf("\n");formMirror(tree);levelWalk(tree);printf("\n");return 0;}


第17题:
题目:在一个字符串中找到第一个只出现一次的字符。如输入abaccdeff,则输出b。   

#include <stdio.h>#include <assert.h>#include <stdlib.h>#include <string.h>void findTheFirstSingle(char *str,int len){if(str==NULL){printf("argument error\n");exit(-1);}assert(len>0);char flag[256];memset(flag,0,256);char *p=str;int i;int index;for(i=0;i<len;i++){index=(int)(*(p+i));flag[index]+=1;}for(i=0;i<256;i++){if(flag[i]==1){printf("the char is %c\n",i);break;}}}int main(){char *str="abaccdef";findTheFirstSingle(str,strlen(str));return 0;}


第18题:
题目:n个数字(0,1,…,n-1)形成一个圆圈,从数字0开始,
每次从这个圆圈中删除第m个数字(第一个为当前数字本身,第二个为当前数字的下一个数字)。
当一个数字删除后,从被删除数字的下一个继续删除第m个数字。
求出在这个圆圈中剩下的最后一个数字。

/** *function : int delNum(int n,int m); *description: there are n persons,marked as 0,1,...n-1; *and they form a circle,now from 0,to n-1,then back to 0 ; *now from 0,begin count,if someone meet m ,then that person is removed. *the next person begin from 0,and keep removing the nth person. *remove n-1 times,then find the last person. *this algorithm is some kind of  complex. * */ #include <stdio.h>#include <stdlib.h>#include <assert.h>struct _node{int data;char flag;struct _node *next;};typedef struct _node  node;int delNum(int n,int m){assert(n>0);assert(m>0);node *header=NULL;node *tail=NULL;int i;for(i=0;i<n;i++){//initnode *tmp=(node *)malloc(sizeof(node));tmp->data=i;tmp->flag=1;if(i==0){header=tmp;tail=tmp;tmp->next=tmp;}tail->next=tmp;tail=tmp;tmp->next=header;}node *cycle=header;node *pre=NULL;for(i=0;i<n-1;i++){ //do n-1 times deleteint counter=0;while(counter<=m){if(counter==m){printf("delete val %d\n",pre->data);pre->flag=0;break;}if(cycle->flag==1){counter++;pre=cycle;cycle=cycle->next;}else{pre=cycle;cycle=cycle->next;}}}node *p=header;while(p!=tail){if(p->flag==1){printf("left value is %d\n",p->data);}node *next=p->next;free(p);p=next;}if(tail->flag==1){printf("left value is %d\n",p->data);}free(tail);return 0;}int main(){delNum(5,3);return 0;}


第19题:
题目:定义Fibonacci数列如下:   
  / 0 n=0
f(n)= 1 n=1
  / f(n-1)+f(n-2) n=2

输入n,用最快的方法求该数列的第n项。

/* *this algorithm compute the fibonacci values *function prototype *int fib(int n); */#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <string.h>int fib(int n){assert(n>=0);int *p=(int *)malloc(4*(n+1));memset(p,0,4*(n+1));p[0]=0;p[1]=1;int i;for(i=2;i<=n;i++){p[i]=p[i-1]+p[i-2];printf("p[%d]=%d\n",i,p[i]);}return p[n];free(p);}int main(){fib(10);}



第20题:
题目:输入一个表示整数的字符串,把该字符串转换成整数并输出。
例如输入字符串"345",则输出整数345。

/*description: *this algorithm change digital numbers to integer *such as ,turn "345" int the integer 345 *  attention here ignored some of the type check*/#include <stdio.h>#include <stdlib.h>int strToInt(char *str,int len){//simple argument checkif((!str)||(len<=0)){printf("argument error\n");exit(-1);}//here ignored to check the character 0-9if(len==1){int val=(*str)-'0';return val;}else{int val=strToInt(str,len-1);char *p=str+len-1;int ret=10*val+(*p)-'0';return ret;}}int main(int argc,char **argv){char *test="5234";int ret=strToInt(test,4);printf("the value is %d\n",ret);return 0;}




原创粉丝点击