1.【美团】有n个球,两我的轮流取球,一次能够取1或2或3个球,取到最后一个球则获胜,请问如何取才能获胜?node
分析:数组
①因为能够连续取球,因此不管另外一我的如何取球,咱们均可以根据他取的球数控制在4个(如:他1个我3个,他2个我2个,他3个我1个);函数
②当最后一轮剩4个球,并且轮到另外一我的取球,那么我就一定能够赢;spa
那么假设我先取a个球,而后两人取球回合为k轮,那么由上面两点能够知道,n=a+4*k且须要注意a>0。设计
所以,当球数为a+4*k时(a≠0),第一个取球的必赢,第一次取的球数使得剩余球数为4*k;当球数为4*k时(a=0),第一个取球的必输。指针
2.【美团】有n个球,两我的轮流取球,一次能够取1或2或4个球,取到最后一个球则判为输,请问如何取才能获胜?code
分析:(题1的变种题)blog
①因为不能够连续取球,因此没法控制每轮取球数目,但有以下关系:排序
当另外一我的取1个球:一轮能够取出2,3,5个球;递归
当另外一我的取2个球:一轮能够取出3,4,6个球;
当另外一我的取4个球:一轮能够取出5,6,8个球;
那么当每轮取球,我能够把取球数控制在3或6,即3*k(k=1,2);
②最后一轮剩余4个球时,不管另外一我的如何取,都会赢;
那么假设我先取a个球,而后两人取球回合为k轮(最后一轮剩4个),每轮取球数为3或6,因此n=a+3*k''+4且须要注意a>0。
所以,当球数n:在n-4后为3的倍数时(a=0),第一个取球的必输;当n-4不为3的倍数(即保证a>0),第一个取球的必赢。此结论对于n=1,2,3,4一样适用。
3.【人人】有两个空酒瓶,容量分别为4斤和5斤,有两个满酒的酒桶,要求分得两个酒瓶均有2斤酒,求分法。
分析:经典的BFS题(请查阅分酒)
尝试分酒完成前一步的酒瓶与酒桶状态:
4斤酒瓶 5斤酒瓶 酒桶1 酒桶2
2 5 -3 -4
4 2 -2 -4
利用这个结果能够往好的方向猜测,下面给出一种分发
4斤酒瓶 | 5斤酒瓶 | 酒桶1 | 酒桶2 |
0 | 0 | 0 | 0 |
4 | 0 | -4 | 0 |
0 | 4 | -4 | 0 |
4 | 4 | -8 | 0 |
3 | 5 | -8 | 0 |
3 | 0 | -3 | 0 |
0 | 3 | -3 | 0 |
4 | 3 | -3 | -4 |
2 | 5 | -3 | -4 |
2 | 2 | 0 | -4 |
#include <stdio.h> #include <stdlib.h> typedef struct node{ int key; struct node *next; }node; int main(void){ node *head, *temp, *pre; node *p1,*p2,*p3; int n, nk; scanf("%d", &n); for(nk=0,pre=NULL; nk<n; nk++){ temp = (node*)malloc(sizeof(node)); scanf("%d", &temp->key); temp->next = NULL; if(nk==0) head = temp; if(pre!=NULL) pre->next = temp; pre = temp; } for(temp=head; temp!=NULL; temp=temp->next){ printf("%d ", temp->key); } printf("\n"); for(p1=NULL, p2=head, p3=head->next; p3!=NULL; p1=p2, p2=p3, p3=temp){ temp = p3->next; p2->next = p1; p3->next = p2; } head = p2; for(temp=head; temp!=NULL; temp=temp->next){ printf("%d ", temp->key); } printf("\n"); system("pause"); return 0; }
5.【美团】对一个单向链表进行冒泡排序,要求修改链表顺序而非交换节点数值。
#include <stdio.h> #include <stdlib.h> typedef struct node{ int key; struct node *next; }node; int main(void){ node *head, *temp, *pre; node *p1,*p2,*p3, *pend, *pnext, *ptemp; int n, nk, flag; scanf("%d", &n); for(nk=0,pre=NULL; nk<n; nk++){ temp = (node*)malloc(sizeof(node)); scanf("%d", &temp->key); temp->next = NULL; if(nk==0) head = temp; if(pre!=NULL) pre->next = temp; pre = temp; } for(temp=head; temp!=NULL; temp=temp->next){ printf("%d ", temp->key); } printf("\n"); for(temp=head; temp!=NULL; temp=temp->next){ for(p1=NULL, p2=head, p3=head->next, pend=NULL, flag=0; p3!=pend; p1=p2, p2=p3, p3=pnext){ pnext = p3->next; if(p2->key>p3->key){ flag = 1; if(p1!=NULL) p1->next = p3; else head = p3; p2->next = p3->next; p3->next = p2; if(temp==p2) temp = p3; //修正p2,p3 ptemp = p2; p2 = p3; p3 = ptemp; } } pend = p2; if(flag==0) break; } for(temp=head; temp!=NULL; temp=temp->next){ printf("%d ", temp->key); } printf("\n"); system("pause"); return 0; }
6.【360】假设表达式能够由an*x^n+an-1*x^(n-1)+...+a1*x+a0来表示(ai不全为0,ai=0或1),在x未知a[n]已知的状况下,至少须要进行多少次乘法运算才能获得全部项?(好比x^3+x^2+x至少须要2次乘法,便可获得x, x^2, x^3)
(待解答)
7.【人人】设计一个函数,判断系统大小端。
分析:为了看清系统大小端,那么只须要查看int型数如何存储便可。
①大端系统-->高字节存到低地址,低字节存到高地址;小端系统-->低字节存到低地址,高字节存到高地址;
②数组a[n],存储地址由小到大分别为&a[0], &a[1], &a[2], ... , &a[n-1];
已知这些条件,利用数组地址分配关系观察int型或者其余类型的数据存储方式,就能够得出系统大小端问题。
运行下面的程序能够一目了然:
#include <stdio.h> #include <stdlib.h> union judge_big_little{ unsigned int a; unsigned char b[4]; }; int main(void){ union judge_big_little myjudge; myjudge.a=0x12345678; printf("%p,%p,%p,%p\n", &myjudge.b[0], &myjudge.b[1], &myjudge.b[2], &myjudge.b[3]); printf("%x,%x,%x,%x\n", myjudge.b[0], myjudge.b[1], myjudge.b[2], myjudge.b[3]); if(myjudge.b[0]==0x12) printf("big endian\n"); else if(myjudge.b[0]==0x78) printf("little endian\n"); system("pause"); return 0; }
8.【人人】设计一个函数,判断所输入的字符串是否为ipv4地址,每一个8位地址前加0视为可行。(如:00212.00012.232.12是正确的ipv4地址)
分析:先总结判断ipv4地址是否正确的几个条件,是一道考察逻辑分析能力的题目。
①是否存在有'0'~'9'或'.'意外的字符;
②'.'出现次数是否低于或超过3次;
③每8位是否超过表示范围(0~255)。
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void){ char s[100]; int slen, k; int iptemp, fuhao_cnt, error_flag; while(1){ gets(s); slen=strlen(s); if(slen==0) break; if(*s=='.'||*(s+slen-1)=='.'){ printf("O,oh!!!\n"); continue; } for(k=0, iptemp=0, fuhao_cnt=0, error_flag=0; k<slen; k++){ if(*(s+k)!='.'&&(*(s+k)<'0'||*(s+k)>'9')){ error_flag=1; break; } if(*(s+k)=='.'){ iptemp=0; fuhao_cnt++; if(fuhao_cnt>3){ error_flag=1; break; } } else{ iptemp=iptemp*10+*(s+k)-'0'; if(iptemp>255){ error_flag=1; break; } } } if(fuhao_cnt!=3) error_flag=1; if(error_flag) printf("O,oh!!!\n"); else printf("bingo\n"); } system("pause"); return 0; }
9.【人人】求一个数列第n个元素,3*i,5*j,i,j都是从1开始,而后输出前n个数,若是同时知足能被3和5整除只显示一遍,例如3,5,6,9,10,12,15,18。
分析:
从0到3,5的最小公倍数15之间有元素3, 5, 6, 9, 10, 12, 15共7个;
从15到3,5的最小公倍数*2=30之间有元素18, 20, 21, 24, 25, 27, 30共7个;
所以,可得规律:当求第n个元素时,可得元素位于15*(n-1)/7与15*((n-1)/7+1)之间,而一个区间内元素偏移量分别为pianyiliang[7]={3, 5, 6, 9, 10, 12, 15}。
得知以上规律能够快速得出所求值=15*(n-1)/7+pianyiliang[(n-1)%7]。
如:
所求数为第7个,则元素为15*(7-1)/7+pianyiliang[(7-1)%7]=15;
所求数为低12个,则元素为15*(12-1)/7+pianyiliang[(12-1)%7]=25。
10.【360】求一棵二叉树的高度。
分析:只须要将树遍历一遍,便可得知树的高度;使用递归能够轻松解决问题。
#include <stdio.h> #include <stdlib.h> typedef struct node{ struct node* lc; struct node* rc; int id; }treenode; //输入1 2 4 # # 5 8 # # 9 10 # # # 3 6 # 11 # # 7 # # void preorder_create_tree(treenode **T){ char ch; int fuhao=1, datatemp; setbuf(stdin, NULL); ch = getchar(); datatemp = 0; while(ch!='\n'&&ch!='#'){ if(ch=='-') fuhao = -1; else datatemp = datatemp*10+ch-'0'; //setbuf(stdin, NULL); ch = getchar(); } datatemp = fuhao*datatemp; if(ch=='#'){ *T = NULL; return; } else{ *T = (treenode*)malloc(sizeof(treenode)); (*T)->id = datatemp; preorder_create_tree(&(*T)->lc); preorder_create_tree(&(*T)->rc); } } void pre_visit(treenode *T){ //递归法 if(T!=NULL){ printf("%d ", T->id); pre_visit(T->lc); pre_visit(T->rc); } else{ return; } } int count_height(treenode* T){ static int h_max=0; static int h=0; if(T==NULL){ if(h>h_max) h_max=h; return; } h++; count_height(T->lc); count_height(T->rc); h--; return h_max; } int main(void){ treenode *tree; preorder_create_tree(&tree); pre_visit(tree); printf("\n"); printf("height is:%d\n", count_height(tree)); system("pause"); return 0; }