每日微软面试题

每日微软面试题——day 1

<以下微软面试题全来自网络>

<以下答案与分析纯属个人观点,不足之处,还望不吝指出^_^>

题:.编写反转字符串的程序,要求优化速度、优化空间。

分析:构建两个迭代器p 和 q ,在一次遍历中,p的位置从字串开头向中间前进,q从字串末尾向中间后退,反转字串只要每次遍历都交换p和q所指向的内容即可,直到p和q在中间相遇,这时循环次数刚好等于 字串的长度/2。

实现代码:


  1. /** 
  2. author: 花心龟 
  3. blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5.   
  6. #include <stdio.h>  
  7. void reverse(char *_str,int _l) //反转函数,_l指要反转字串的长度  
  8. {  
  9.  char *p=_str,*q=_str+_l-1,temp;  
  10.   
  11.  while(q>p)  
  12.    {   
  13.      temp=*p;  
  14.      *p=*q;  
  15.      *q=temp;  
  16.    
  17.      p++;  
  18.      q--;  
  19.    }  
  20. }  
  21.    
  22. int main()  
  23. {  
  24.   charstr0[11]= "0123456789";       
  25.  reverse(str0,sizeof(str0)-1);  
  26.  printf("str0 = %s\n",str0);  
  27.    
  28.   char str1[6]="01234";  
  29.  reverse(str1,sizeof(str1)-1);  
  30.  printf("str1 = %s",str1);  
  31.   return 0;  
  32. }  



题:.在链表里如何发现循环链接?

分析:可以构建两个迭代器p和pp,p一次向移动一个节点,pp一次移动两个节点,如果p和pp在某个时刻指向了同一个节点,那么该链表就有循环链接。

实现代码:

  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5. #include <stdio.h>  
  6. #include <malloc.h>  
  7.   
  8. #define TEST  
  9.   
  10. struct list_node  
  11. {  
  12.   int data;  
  13.   list_node * next;  
  14. };  
  15. list_node *head; //指向头结点  
  16.   
  17. void list_create()  
  18. {  
  19.   int i;  
  20.   list_node *p=NULL;  
  21.   head = (list_node*)malloc(sizeof(list_node));  
  22.   head->data=0;     //头结点数据设为  
  23.   head->next = NULL;  
  24.   
  25.   p=head;  
  26.   for(i=1; i<6; i++) //创建个结点  
  27.     {  
  28.       p->next = (list_node*)malloc(sizeof(list_node));  
  29.       p->next->data = i;  
  30.       p->next->next = NULL;  
  31.       p=p->next;  
  32.     }  
  33.   p->next = head;  //使尾结点的下一个结点指针指向头结点,构成循环链表  
  34.   
  35. #ifdef TEST  
  36.   p=head;  
  37.   for(i=0; i<12&&p!=NULL; i++)  
  38.     {  
  39.       printf("%d ",p->data);  
  40.       p=p->next;  
  41.     }  
  42.   printf("\n");  
  43. #endif  
  44. }  
  45.   
  46. void cycleList_test()  
  47. {  
  48.   if(head==NULL || head->next == NULL)  
  49.       return;  
  50.   list_node *p=NULL,*pp=NULL;  
  51.   p=head;  
  52.   pp=head->next->next;  
  53.   while(p!=pp )  
  54.     {  
  55.       p=p->next;  
  56.       pp=pp->next->next;  
  57.   
  58.       if(p==NULL || pp==NULL)  
  59.     {  
  60.       printf("不是循环链表");  
  61.       return ;  
  62.     }  
  63.     }  
  64.   printf("是循环链表");  
  65. }  
  66.   
  67. void list_destroy()  
  68. {  
  69.   list_node *pmove=NULL,*pdel=NULL;  
  70.   pmove=head->next;  
  71.   
  72.  while(pmove!=head)  
  73.    {  
  74.      pdel=pmove;  
  75.      pmove=pmove->next;  
  76.      free(pdel);     
  77.    }  
  78.   
  79.   free(head);  
  80. }  
  81. int main()  
  82. {  
  83.   list_create();   //构建循环链表  
  84.   cycleList_test();//测试是否是循环链表  
  85.   list_destroy();  //销毁链表  
  86.   return 0;  



题:.给出洗牌的一个算法,并将洗好的牌存储在一个整形数组里。

分析:首先54张牌分别用0到53 的数值表示并存储在一个整形数组里,数组下标代表纸牌所在的位置。接下来,遍历整个数组,在遍历过程中随机产生一个随机数,并以该随机数为下标的数组元素与当前遍历到的数组元素进行对换。时间复杂度为O(n) (注:所得到的每一种结果的概率的分母越大越好)

实现代码:

  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5.   
  6. #include <stdio.h>  
  7. #include <time.h>  
  8. #include <stdlib.h>  
  9.   
  10. void shuffle(int boke[])  //洗牌  
  11. {  
  12.   int i,r,t;  
  13.   srand((unsigned)time(NULL)); //随机数种子  
  14.   for(i=0; i<54; i++)  
  15.     {  
  16.       r=(rand()%107)/2;  
  17.   
  18.       //交换  
  19.       t=boke[i];  
  20.       boke[i]=boke[r];  
  21.       boke[r]=t;  
  22.     }  
  23. }  
  24.   
  25. int main()  
  26. {  
  27.   int boke[54],i;  
  28.   for(i=0;i<54;i++) //初始化纸牌  
  29.     boke[i]=i;  
  30.   
  31.   printf("before shuffle:\n");  
  32.   for(i=0; i<54; i++)    //打印  
  33.       printf("%d ",boke[i]);  
  34.   
  35.   
  36.   shuffle(boke);     //洗牌  
  37.   
  38.   
  39.   printf("\nafter shuffle:\n");  
  40.   for(i=0; i<54; i++)   //打印  
  41.       printf("%d ",boke[i]);  
  42.   
  43.   return 0;  
  44. }  



题:写一个函数,检查字符串是否是整数,如果是,返回其整数值。

(或者:怎样只用4行代码编写出一个从字符串到长整形的函数?)

分析:略

实现代码:

  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5.   
  6. #include <stdio.h>  
  7.   
  8. long convert(const char *str) // 4行代码?下面我用了四句语句,不知当不当否,权当娱乐^^  
  9. {  
  10.   long value=0,f=1;     //f将决定value是否为负数  
  11.   
  12.   if(*str == '-') str++,f=-1;  
  13.   
  14.   for(;*str!='\0' && *str>='0' && *str<='9'; str++)  
  15.     value=value*10+(*str-'0');    
  16.   
  17.   return *str=='\0'?value*f:0;  //如果不为整数返回  
  18. }  
  19.   
  20. int main()  
  21. {  
  22.   
  23.   char str0[] = "1234567";  
  24.   printf("%d\n",convert(str0));  
  25.   
  26.   char str1[] = "4.56";  
  27.   printf("%d\n",convert(str1));  
  28.   
  29.   char str2[] = "-1234567";  
  30.   printf("%d\n",convert(str2));  
  31.   
  32.   char str3[] = "-4.56";  
  33.   printf("%d\n",convert(str3));  
  34.     
  35.   return 0;  



题:怎样从顶部开始逐层打印二叉树结点数据?请编程。

分析不用递归,定义两个栈(或数组),也能方便漂亮地搞定。首先栈1存储第一层中的节点也就是根节点,然后每次循环,打印栈1中的元素,再将栈1中的节点更新为下一层中的节点。总共循环logn+1次。


实现代码(以下遗漏了对二叉树的销毁操作):


  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5. #include <stdio.h>  
  6. #include <malloc.h>  
  7.   
  8. typedef struct bt_node  
  9. {  
  10.   int data;  
  11.   struct bt_node *rchild;  
  12.   struct bt_node *lchild;  
  13. }BinTree,node_t;  
  14.   
  15. BinTree *myTree;  
  16.   
  17. node_t* bt_new_node(int data)  
  18. {  
  19.   node_t* node = (node_t*)malloc(sizeof(node_t));  
  20.   node->rchild = NULL;  
  21.   node->lchild = NULL;  
  22.   node->data = data;  
  23.   
  24.   return node;  
  25. }  
  26. void bt_create()  
  27. {  
  28.   //第一层根节点,数字11表示第一层的第一个位置,以下类似  
  29.   myTree = bt_new_node(11);  
  30.   
  31.   //创建第二层节点   
  32.   myTree->lchild = bt_new_node(21);  
  33.   myTree->rchild = bt_new_node(22);   
  34.   
  35.   
  36.   //创建第三层节点  
  37.   myTree->lchild->lchild = bt_new_node(31);  
  38.   myTree->lchild->rchild = bt_new_node(32);  
  39.   myTree->rchild->lchild = bt_new_node(33);  
  40.   myTree->rchild->rchild = bt_new_node(34);  
  41.   
  42.   //创建第四层节点  
  43.   myTree->rchild->rchild->rchild = bt_new_node(48);  
  44. }  
  45.   
  46. void print_layer_by_layer()  //逐层打印二叉树非递归算法(主题)  
  47. {  
  48.   node_t* stack1[100]={0};//栈  
  49.   node_t* stack2[100]={0};//栈  
  50.   int T1=0,T2=0;           //栈顶下标  
  51.   
  52.   
  53.   stack1[T1++]=myTree;   //根节点入栈  
  54.   while(T1) //若栈为空则停止循环  
  55.     {  
  56.       while(T1)  
  57.     {  
  58.       T1--;  
  59.       printf("%d ",stack1[T1]->data); //打印栈顶元素  
  60.       stack2[T2++]=stack1[T1];        //将栈元素转存到栈2中  
  61.     }  
  62.       printf("\n");  
  63.   
  64.       //此时栈已存储了当前行的各元素  
  65.       //通过栈得到下一行中的节点并更新到栈中  
  66.       while(T2)    
  67.     {  
  68.       T2--;  
  69.       if(stack2[T2]->rchild != NULL)  
  70.         stack1[T1++]=stack2[T2]->rchild;  
  71.   
  72.       if(stack2[T2]->lchild != NULL)  
  73.         stack1[T1++]=stack2[T2]->lchild;  
  74.     }  
  75.     }  
  76. }  
  77. int main()  
  78. {  
  79.   bt_create();            //创建二叉树  
  80.   print_layer_by_layer(); //逐层打印  
  81.   return 0;  
  82. }  

另:关于此题的其它想法请看3楼我的回复,回复上的编码步骤为广度优先遍历二叉树算法,不过本人不才哈,不知题目中的意思是一层一层的打印呢,还是按照层的顺序从左到右一个一个打印呢(好像也是逐层打印),且不管它,通过对两种算法比较,上面使用栈的算法功能更强,至少打完一层可以再打一个回行。而使用队列的广度优先遍历二叉树算法有效率优势,且代码简洁易懂,就是不能打完一层后回行。^_^ 纯属个人观点,望不吝指教。


题:怎样把一个链表掉个顺序(也就是反序,注意链表的边界条件并考虑空链表)?

分析:这题比较有意思,我想了个高效的实现。首先定义两个迭代器 p 和 q,q从第一个节点开始遍历,p从第二个节点开始遍历,每次遍历将头指针的next指向p的next,然后将p的next 反指向q(此时q是p的前一个节点),也就是说将每个节点的链接方向掉过来,最后尾节点变成了头节点,头节点变成了尾节点,时间复杂度为高效的O(n)


图示:(最后一个N指空节点)


以下便是是我简洁的实现代码:

  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5.    
  6. #include <stdio.h>  
  7. #include <malloc.h>  
  8.    
  9. #define TEST  
  10.    
  11. typedef struct list_node  
  12. {  
  13.   int data;  
  14.   structlist_node * next;  
  15. }list_node;  
  16.    
  17. list_node *head; //头结点  
  18.    
  19. void list_create()  
  20. {  
  21.   int i;  
  22.   list_node *p;  
  23.   head = (list_node*)malloc(sizeof(list_node));  
  24.   head->data=0;     //头结点数据设为  
  25.   head->next = NULL;  
  26.    
  27.   p=head;  
  28.   for(i=1;i<6; i++) //创建5个结点  
  29.     {  
  30.       p->next = (list_node*)malloc(sizeof(list_node));  
  31.       p->next->data = i;  
  32.       p->next->next = NULL;  
  33.       p=p->next;  
  34.     }  
  35.    
  36. #ifdef TEST  
  37.   p=head;  
  38.   while(p!=NULL)   //打印该链表  
  39.     {  
  40.       printf("%d",p->data);  
  41.       p=p->next;  
  42.     }  
  43.   printf("\n");  
  44. #endif  
  45. }  
  46.    
  47. void list_reverse()  //使链表反序 (主题)  
  48. {  
  49.   printf("^^after reversing:\n");  
  50.   if(head == NULL || head->next==NULL) return ;//如果head为空,则返回  
  51.   list_node *p,*q;  
  52.   q=head;  
  53.   p=head->next;  
  54.    
  55.   while(p!=NULL)  
  56.     {  
  57.     head->next=p->next; //将头指针的next指向p的下一个节点  
  58.     p->next=q;          //将p的next值反指向它的前一个节点q  
  59.     q=p;                //q移向p的位置  
  60.     p=head->next;       //p移向它的下一个位置  
  61.     }  
  62.      
  63.     head = q;  
  64.    
  65. #ifdef TEST  
  66.   p=head;  
  67.   while(p!=NULL)        //打印该链表  
  68.     {  
  69.       printf("%d",p->data);  
  70.       p=p->next;  
  71.     }  
  72.   printf("\n");  
  73. #endif  
  74.    
  75. }  
  76.    
  77. void list_destroy()  //销毁函数  
  78. {  
  79.   list_node *pmove=NULL,*pdel=NULL;  
  80.   pmove=head;  
  81.    
  82.  while(pmove!=head)  
  83.    {  
  84.      pdel=pmove;  
  85.      free(pdel);    
  86.      pmove=pmove->next;  
  87.    }  
  88. }  
  89. int main()  
  90. {  
  91.   list_create();   //构建单链表  
  92.   list_reverse();  //反转链表  
  93.   list_destroy();  //销毁链表  
  94.   return 0;  



题:求随机数构成的数组中找到长度大于=3的最长的等差数列

输出等差数列由小到大: 

如果没有符合条件的就输出[0,0]

格式:

输入[1,3,0,5,-1,6]

输出[-1,1,3,5]

要求时间复杂度,空间复杂度尽量小

分析基本算法思路(采用动态规划思想):首先,只要得到数列的公差和一个首项就可以确定一个等差数列,因此我们要寻找最长等差数列的公差以及首项。其次,为了方便查找公差和首项,我们应该将原数组进行由小到大排序,这样各两数之间的公差也是成递增形势的,这样我们就可以避免回溯查找首项

因此,在搜寻公差及首项的过程中,我们可以分两三个决策阶段:

1、如果公差为0,应该做何处理。

2、如果公差不为0,应该做何处理。

3、如果找到的数列长度是当前最长的做相应的处理

      针对以上情况,我们应该选择一种合适的数据结构——平衡排序树,stl中的set,map,mutiset,multimap是以红黑树结构为形势的容器,无疑是非常合适的,根据题目情况,可能存在具有相同元素的数组,因此我们选择multiset,这样无论我们对数据进行插入排序,查找都是比较高效的,因此总体上是可以满意的。

      最后有几项时间上的优化不在这里说明,详情可看代码。若有不足之处,望能不吝指出!^_^


我的实现代码:


  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5. #include <iostream>  
  6. #include <ctime>  
  7. #include <set>  
  8. using namespace std;  
  9.   
  10. void show_longest_seq(const multiset<int>& myset)  
  11. {  
  12.     int maxLength = 0, curr_pos = 0, curr_d = 0, counter=0,i=0; //一些辅助变量  
  13.     int d_result, a1_result; //存储最长等差数列的公差以及首项  
  14.     multiset<int>::const_iterator set_it1,set_it2;  
  15.   
  16.       
  17.     /* 
  18.          (主题)寻找长度最长的等差数列,最坏情况下时间复杂度为O(n^3) 
  19.     */  
  20.     for(set_it1 = myset.begin(); set_it1 != myset.end();)  
  21.     {  
  22.         for(set_it2=set_it1,set_it2++; set_it2 != myset.end();)//第二层循环从set_it1所指的下一个元素开始遍历  
  23.         {  
  24.             curr_d = *set_it2 - *set_it1; //算得当前公差,注意由于set为自排序容器,从小到大排列,所以curr_d恒为正  
  25.   
  26.             if(curr_d == 0) // 如果公差为0  
  27.             {  
  28.                 counter = myset.count(*set_it1);  
  29.                 set_it2 = myset.upper_bound(*set_it1);//(优化项)跳过与set_it1相等的元素  
  30.             }  
  31.             else  
  32.             {  
  33.                 counter = 2; //(优化项)最小长度要求要不小于所以直接从开始累加  
  34.                 while(myset.find(*set_it1 + counter*curr_d) != myset.end()) //计算数列项个数  
  35.                     ++counter;  
  36.   
  37.                 set_it2 = myset.upper_bound(*set_it2);// (优化项)跳过与*set_it2相等的元素  
  38.             }  
  39.   
  40.               
  41.             if(counter > maxLength)  //如果新数列长度大于maxLength  
  42.             {  
  43.                 d_result = curr_d;  
  44.                 a1_result = *set_it1;  
  45.                         maxLength = counter;  
  46.             }  
  47.         }  
  48.   
  49.         curr_pos += myset.count(*set_it1);     //计算第一层循环遍历到的当前位置  
  50.         if(myset.size()-curr_pos < maxLength)  // (优化项)如果集合中剩下的元素小于最大数列长度,就退出循环  
  51.             break;  
  52.   
  53.         set_it1 = myset.upper_bound(*set_it1); //下一次set_it1 的位置,并跳过相同元素  
  54.     }  
  55.   
  56.   
  57.   
  58.   
  59.     /* 
  60.        打印最长等差数列 
  61.     */  
  62.     if(maxLength <= 2)  
  63.     {  
  64.         cout<<"longest_seq:[0,0]"<<endl;  
  65.     }  
  66.     else  
  67.     {  
  68.         cout<<"longest_seq:";  
  69.           
  70.         for(i = 0; i<maxLength;  i++)  
  71.             cout<<*(myset.find(a1_result + i*d_result))<<' ';  
  72.   
  73.         cout<<endl;  
  74.     }  
  75. }  
  76. //Blog:http://blog.csdn.net/zhanxinhang  
  77.  test in main  
  78. int main()  
  79. {  
  80.     int a[]={1,3,0,5,-1,6};  
  81.     multiset<int> myset;  
  82.     myset.insert(a,a+6);  
  83.     show_longest_seq(myset);  
  84.     cout<<endl;  
  85.   
  86.     int l;  
  87.     srand((unsigned)time(NULL));  
  88.     for(int j = 0; j < 5; j++)  
  89.     {  
  90.         myset.clear();  
  91.         cout<<"input:[ ";  
  92.         l=rand()%10;  
  93.         for(int i = 0; i < l; ++i)  
  94.         {  
  95.             int element = rand()%10;  
  96.             myset.insert(element);  
  97.             cout<<element<<' ';  
  98.         }  
  99.         cout<<']'<<endl;  
  100.         show_longest_seq(myset);  
  101.         cout<<endl;  
  102.     }  
  103.   
  104.   
  105.     return 0;  
  106. }  


附一张测试结果图:





题:两个链表,一升一降。合并为一个升序链表。

分析假设升序的链表为链表1,降序的链表为链表2,p1,p2分别作为它们的迭代器,还有一个合并链表用于存放合并后的数据

法一、最容易想到的且容易实现的就是使两个表都变成升序,然后就是经典的合并排序算法的步骤了,步骤是构建p1,p2两个迭代器,分别用于迭代两个链表,每次遍历,若p1所指的节点数据大于p2所指的节点数据则将p1所指的节点数据插入到要合并链表中去且使p1指向下一个节点,否则将p2将所指的节点数据插入到合并链表中去且使p2指向下一个节点,直到p1和p2任意一个指向了NULL为止。最后可能两个链表中尚有剩余的节点,将其逐个插入到合并链表中去即可。

法二、使用递归方法后序遍历降序链表2,遍历顺序就相当于升序的顺序了。在递归遍历链表2的过程中,需要处理有以下三件事:(注意顺序)

(1) 如果p2的数据小于p1的就插入到合并链表中
(2) 如果p2的数据大于p1,那么就对链表1循环遍历,每次将p1中的数据插到合并链表中,直到p2不大于p1,且p1不为空

(3) 如果p1为空,就直接将p2插入到合并链表中

(这个方法你想到了没!)

完整实现代码:
  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5.    
  6. #include <stdio.h>  
  7. #include <malloc.h>  
  8. #include <stdlib.h>   
  9.   
  10. typedef struct list_node  
  11. {  
  12.   int data;  
  13.   struct list_node * next;  
  14. }list_node;  
  15.    
  16. list_node *list1=NULL; //链表头结点  
  17. list_node *list2=NULL; //链表头结点  
  18.   
  19. void list_print(const list_node *p)//打印该链表函数  
  20. {  
  21.   if(p==NULL)return;  
  22.   while(p!=NULL)     
  23.     {  
  24.       printf("%d ",p->data);  
  25.       p=p->next;  
  26.     }  
  27.   printf("\n");  
  28. }  
  29.   
  30. void list_create(list_node* &head, int data[], int N)  
  31. {  
  32.   if(data == NULL) return;  
  33.   
  34.   int i;  
  35.   list_node *p;  
  36.   p = (list_node*)malloc(sizeof(list_node));  
  37.   p->data = data[0];  
  38.   p->next = NULL;  
  39.   head = p;   
  40.   for(i=1;i<N; i++)   
  41.     {  
  42.       p->next = (list_node*)malloc(sizeof(list_node));  
  43.       p->next->data = data[i];  
  44.       p->next->next = NULL;  
  45.       p=p->next;  
  46.     }  
  47. }  
  48.   
  49. void list_reverse(list_node* &head)  //使链表反序  
  50. {  
  51.   if(head == NULL) return ;//如果head1为空,则返回  
  52.   list_node *p,*q;  
  53.   q=head;  
  54.   p=head->next;  
  55.    
  56.   while(p!=NULL)  
  57.     {  
  58.     head->next=p->next; //将头指针的next指向p的下一个节点  
  59.     p->next=q;          //将p的next值反指向它的前一个节点q  
  60.     q=p;                //q移向p的位置  
  61.     p=head->next;       //p移向它的下一个位置  
  62.     }  
  63.   
  64.     head = q;  
  65. }  
  66.   
  67. void list_destroy(list_node *head)  //销毁函数  
  68. {  
  69.   list_node *pmove=NULL,*pdel=NULL;  
  70.   pmove=head;  
  71.    
  72.  while(pmove!=head)  
  73.    {  
  74.      pdel=pmove;  
  75.      free(pdel);    
  76.      pmove=pmove->next;  
  77.    }  
  78. }  
  79.   
  80. list_node* merge_two_list() //合并链表1和链表2(法一)  
  81. {  
  82.     list_reverse(list2);    //反转链表使之与链表一样升序排列  
  83.     list_node *list_merged;  //和并后的链表  
  84.     list_node *p1,*p2,*p0;        
  85.     list_merged = (list_node*)malloc(sizeof(list_node));  
  86.     list_merged->data = 0;  
  87.     list_merged->next = NULL;  
  88.     p0 = list_merged;  
  89.   
  90.     p1=list1;  
  91.     p2=list2;  
  92.     while(p1!=NULL && p2!=NULL)  
  93.     {  
  94.         if(p1->data < p2->data)  
  95.         {  
  96.             p0->next=(list_node*)malloc(sizeof(list_node));  
  97.             p0->next->data=p1->data;  
  98.             p0->next->next=NULL;  
  99.             p0=p0->next;  
  100.             p1=p1->next;  
  101.         }  
  102.         else  
  103.         {  
  104.             p0->next=(list_node*)malloc(sizeof(list_node));  
  105.             p0->next->data=p2->data;  
  106.             p0->next->next=NULL;  
  107.             p0=p0->next;  
  108.             p2=p2->next;  
  109.         }  
  110.     }  
  111.     while(p1!=NULL)  
  112.     {  
  113.             p0->next=(list_node*)malloc(sizeof(list_node));  
  114.             p0->next->data=p1->data;  
  115.             p0->next->next=NULL;  
  116.             p0=p0->next;  
  117.             p1=p1->next;  
  118.     }  
  119.     while(p2!=NULL)  
  120.     {  
  121.             p0->next=(list_node*)malloc(sizeof(list_node));  
  122.             p0->next->data=p2->data;  
  123.             p0->next->next=NULL;  
  124.             p0=p0->next;  
  125.             p2=p2->next;  
  126.     }  
  127.     return list_merged;  
  128. }  
  129.   
  130.   
  131.   
  132. list_node* p0=(list_node*)malloc(sizeof(list_node));  
  133. list_node* phead=p0;  
  134. list_node* &p1=list1; //p1与list1绑定  
  135. list_node* foreach(list_node* p2) //递归合并(法二)  
  136. {  
  137.     if(p2==NULL) return phead;  
  138.   
  139.     foreach(p2->next);   
  140.   
  141.     if(p1->data > p2->data)  
  142.     {  
  143.         p0->next = (list_node*)malloc(sizeof(list_node));  
  144.         p0->next->data = p2->data;  
  145.         p0->next->next = NULL;   
  146.         p0=p0->next;  
  147.         return phead;  
  148.     }  
  149.     while(p1!=NULL && p1->data<=p2->data)  
  150.     {  
  151.         p0->next = (list_node*)malloc(sizeof(list_node));  
  152.         p0->next->data = p1->data;  
  153.         p0->next->next = NULL;   
  154.         p0=p0->next;  
  155.         p1 = p1->next;  
  156.     }  
  157.     if(p1==NULL)  
  158.     {  
  159.         p0->next = (list_node*)malloc(sizeof(list_node));  
  160.         p0->next->data = p2->data;  
  161.         p0->next->next = NULL;   
  162.         p0=p0->next;  
  163.     }  
  164.   
  165.     return phead;  
  166. }  
  167. //Blog:http://blog.csdn.net/zhanxinhang  
  168. int main()  
  169. {  
  170.     int list1_data[] = {1,4,6,8,10};    //链表数据升序 可在这里该数据进行测试  
  171.     int list2_data[] = {14,9,3,2};      //链表数据降序  
  172.   
  173.     list_create(list1,list1_data,5);   //构建单链表  
  174.     list_create(list2,list2_data,4);   //构建单链表  
  175.     list_print(list1);  
  176.     list_print(list2);  
  177.   
  178.     //list_node *list_merged=merge_two_list(); //合并两个链表  
  179.     //list_print(list_merged->next);      //打印合并后的链表  
  180.   
  181.     list_node *list_merged2=foreach(list2);    //使用递归合并两个链表  
  182.     list_print(list_merged2->next);  
  183.   
  184.     list_destroy(list1);                //销毁链表  
  185.     list_destroy(list2);                //销毁链表  
  186. //  list_destroy(list_merged);          //销毁合并后的链表  
  187.     list_destroy(list_merged2);         //销毁合并后的链表  
  188.     system("pause");  
  189.     return 0;  
  190. }  


:如何删除链表的倒数第m的元素?

分析构建p0,p1两个迭代器,初始使p0和p1指向头结点,接着使p1移动到第m+1项,然后指向头得p0与p1同时前进,当p1指向空节点的时候结束,这时p0所指的位置就是倒数第m个,时间复杂度为O(n)

实现代码:(为了学习的需要,现在C++朋友采用c++实现,不能满足c朋友要采用c实现的愿望,此实为c++朋友的遗憾,不过一切重在思想。^_^

  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5. #include <iostream>  
  6. #include <list>  
  7. using namespace std;  
  8.   
  9. class App  
  10. {  
  11.     list<int> *plist;   
  12.   
  13.     void delete_node_at_last(int m) //today`s topic  
  14.     {  
  15.         list<int>::iterator p0, p1;  
  16.         p0=p1=p2=plist->begin();  
  17.   
  18.         //使p1移到第m+1项  
  19.         for(int i=1; i<=m; i++)  
  20.             p1++;  
  21.   
  22.         //p0和p1同时前进,当p1到达终点时p0所指向的就是倒数第m个节点  
  23.         while(p1!=plist->end())  
  24.             p0++,p1++;  
  25.   
  26.         //删除节点  
  27.         plist->erase(p0);  
  28.     }  
  29.   
  30.     void create_list()  
  31.     {  
  32.         int list_data[]={1,2,3,4,5,6,7,8,9}; //链表数据  
  33.         plist = new list<int>(list_data, list_data+sizeof(list_data)/sizeof(int));  
  34.     }  
  35.   
  36.     void print_list()  
  37.     {  
  38.         list<int>::iterator it;  
  39.         for(it=plist->begin(); it!=plist->end(); it++)  
  40.             cout<<*it<<' ';  
  41.     }  
  42.   
  43. public:  
  44.     //test in run funtion  
  45.     void run()  
  46.     {  
  47.         create_list();  
  48.         delete_node_at_last(3); //删除倒数第三个节点  
  49.         print_list();  
  50.     }  
  51.   
  52.     ~App()  
  53.     {  
  54.         delete plist;  
  55.     }  
  56. };  
  57. //Blog:http://blog.csdn.net/zhanxinhang  
  58. int main()  
  59. {  
  60. App myapp;  
  61. myapp.run();  
  62. system("pause");  
  63. return 0;  





:1、如何判断一个字符串是对称的?如a,aa,aba。   

         2、如何利用2函数找出一个字符串中的所有对称子串?


分析

        看第一个问题判断字符串对称,有以下两种方法。

        方法一、使迭代器p1指向头,p2指向尾。使p1,p2相对而行(—> | <),每次比较p1,p2是否相等,直到它们相遇。

        方法二、使p1、p2指向中间的一个元素(如果字符串长度为偶数的话就指向中间两个相邻的元素),使它们相向而行(<— |—>),每次比较p1,p2是否相等。直到它们一个指向头一个指向尾便结束。  

(可以看出方法1明显好于方法2)

        在看第二个问题打印所有的对称子串,判断对称子串的问题我们似乎已经解决,且有以上两种方法,针对现在的情况是否两种都合适呢,确切的说不是。如果是方法一,请想象一下,如果要p1,p2一个指向子串的头一个指向子串的尾,那么至少要两层循环一层控制p1一层控制p2,还有一层循环用于判断子串是否对称,也就是说总共需要三层嵌套循环,时间复杂度指数为3。而如果选择方法二呢? 两层循环就能实现,不过要适应现在这种情况需要做些修改,就是针对偶数长度的子串进行一次遍历,再针对奇数长度的子串进行一次遍历,也就是两层嵌套循环中内层有两次循环,时间复杂度指数为2。详情且看代码。


实现加测试代码:

  1. /** 
  2. Author:花心龟 
  3. Blog:http://blog.csdn.net/zhanxinhang 
  4. **/  
  5.   
  6. #include <iostream>  
  7. #include <cstdlib>  
  8. #include <ctime>  
  9. using namespace std;  
  10. class App  
  11. {  
  12.     typedef string::iterator Iter_t;  
  13.   
  14.     string m_str;  
  15.     void print(Iter_t p1, Iter_t p2) //打印从p1开始到p2结束的字符  
  16.     {  
  17.         while(p1<=p2)  
  18.         {  
  19.             cout<<*p1;  
  20.             p1++;  
  21.         }  
  22.         cout<<" | ";  
  23.     }  
  24.     bool isHuiwen1(Iter_t start,Iter_t end) //法1判断是否为对称子串  
  25.     {  
  26.         Iter_t p1 = start;  
  27.         Iter_t p2 = end;  
  28.         int times = (distance(p1,p2)+1) / 2; //比较次数  
  29.         while(times)  
  30.         {  
  31.             if(*p1 != *p2)  
  32.                 return false;  
  33.   
  34.             p1++;   
  35.             p2--;   
  36.             times--;  
  37.         }  
  38.         return true;  
  39.     }  
  40.   
  41.     bool isHuiwen2(Iter_t mid_it) //法2判断是否为对称子串  
  42.     {  
  43.         Iter_t p1,p2;  
  44.         p1 = p2 = mid_it;  
  45.   
  46.         while(p1>=m_str.begin() && p2 < m_str.end())   
  47.         {             
  48.             if(*p1 != *p2)   
  49.                 break;    
  50.             print(p1,p2);//打印从p1到p2的字符  
  51.             p1--,p2++;  
  52.         }  
  53.   
  54.         p1 = p2 = mid_it;  
  55.         p2++; //使p2向前移动一个位置,此时p1,p2分别指向中间两个相邻位置  
  56.         while(p1>=m_str.begin() && p2 < m_str.end())    
  57.         {  
  58.             if(*p1 != *p2)  
  59.                 return false;  
  60.             print(p1,p2);//打印从p1到p2的字符  
  61.             p1--,p2++;  
  62.         }  
  63.         return true;  
  64.     }  
  65.   
  66.     void show_all_substr_of_huiwen1() //法一打印所有对称子串  
  67.     {  
  68.         Iter_t p2=m_str.end()-1;  
  69.         Iter_t p1 = m_str.begin();  
  70.         for(;p1!=m_str.end();p1++)  
  71.             for(p2=p1;p2!=m_str.end();p2++)  
  72.             {  
  73.                 if(isHuiwen1(p1,p2))  
  74.                     print(p1,p2);  
  75.             }  
  76.     }  
  77.   
  78.     void show_all_substr_of_huiwen2()  //法二打印所有对称子串  
  79.     {  
  80.         Iter_t it = m_str.begin();  
  81.   
  82.         for(;it!=m_str.end();it++)  
  83.         {  
  84.             isHuiwen2(it);  
  85.         }  
  86.     }  
  87.   
  88. public:  
  89.   
  90.     void run()  
  91.     {  
  92.         m_str="abaaba";  
  93.         cout<<"测试数据为:abaaba"<<endl;  
  94.         show_all_substr_of_huiwen1();  
  95.         cout<<endl;  
  96.         show_all_substr_of_huiwen2();  
  97.         cout<<endl;  
  98.   
  99.         m_str="asdfie";  
  100.         cout<<"测试数据为:asdfie"<<endl;  
  101.         show_all_substr_of_huiwen1();  
  102.         cout<<endl;  
  103.         show_all_substr_of_huiwen2();  
  104.         cout<<endl;  
  105.   
  106.         m_str="aabaa";  
  107.         cout<<"测试数据为:aabaa"<<endl;  
  108.         show_all_substr_of_huiwen1();  
  109.         cout<<endl;  
  110.         show_all_substr_of_huiwen2();  
  111.         cout<<endl;  
  112.   
  113.         //时间比较//  
  114.         m_str="this is a string for testing. aabaa alskjdfkljasdjflasdflkajsldkjfsjlakjsdlfjwoekjlakjlsdkjflsajlkdjfowieuoriuq aaddbb sldjfalkjsdlfkjasldjflajsldfjalskdjflakjsdlfkjaslkdjflajsdlfkjaslkdjflkajsdlkjflkasjdlfjaklsjdkfljaklsdjfklsajdflkjslkdjflaskjdlfkjalsdjlfkajsldfkjlaksjdfljasldjflaskjdfkasjdflaksjdkfljaskldfjlaksjdfljasldjflaksjdkljfkalsjdlkfjasldjflasjdlfjasldjfklsajdfljaskldfjlsakjdflkasjdfkl this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k is is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.this is a string for testing.make -k make -k make -k make -k make -k make -k end";  
  115.   
  116.   
  117.         time_t start,record1;  
  118.   
  119.   
  120.         cout<<"show all substr of huiwen 1:";  
  121.         system("pause");  
  122.         start = time(NULL);      
  123.         show_all_substr_of_huiwen1();  
  124.         record1 = time(NULL);  
  125.   
  126.         cout<<endl;  
  127.         cout<<"time:"<<record1-start;  
  128.         cout<<endl;  
  129.   
  130.   
  131.         cout<<"show all substr of huiwen 2:";  
  132.         system("pause");  
  133.         start = time(NULL);  
  134.         show_all_substr_of_huiwen2();  
  135.         record1 = time(NULL);  
  136.   
  137.         cout<<endl;  
  138.         cout<<"time:"<<record1-start;  
  139.         cout<<endl;  
  140.   
  141.         cout<<"(可以看到打印速度明显快于上一次)";  
  142.     }  
  143. };  
  144.   
  145. int main()  
  146. {  
  147.     App myapp;  
  148.     myapp.run();  
  149.   
  150.     system("pause");  
  151.     return 0;  
  152. }  

测试结果:

各测试数据下的一二行为打印出来的所有对称字串。

按下任意键后:

以上是使用方法1打印出来的结果。

按下任意键后:

以上便是用方法2打印出来的结果。





假设你有一个用1001个整数组成的数组,这些整数是任意排列的,但是你知道所有的整数都在1到1000(包括1000)之间。此外,除一个数字出现两次外,其他所有数字只出现一次。假设你只能对这个数组做一次处理,用一种算法找出重复的那个数字。如果你在运算中使用了辅助的存储方式,那么你能找到不用这种方式的算法吗?

分析

方法一使用辅助的存储方式该选择何种存储方式呢可使用hash的存储方式,以1到1000作为hash表的索引,遍历原数组,统计各数字出现的个数并存储到以该数字为索引值的hash表中,若某个hash[x]的值为2则退出循环,x就是重复出现两次的数字。时间复杂度最坏是O(n)。优点:高效率,缺点:消耗的内存空间过大。代码如下:

  1. int fun1(const int a[])  
  2. {  
  3.   int hash[1002]={0};  
  4.   int x=0;  
  5.   for(int i = 0; i<1001; i++)  
  6.     {  
  7.       if((++hash[a[i]]) == 2)  
  8.         {  
  9.           x = a[i];  
  10.           break;  
  11.         }  
  12.     }  
  13.   return x;  
  14. }  

方法二若不使用辅助的存储方式呢1001个整数组成的数组只有一个数字出现了两次,且整数都在1到1000之间,所以可推得数组里面包含了1到1000之间的所有数字为[1,2,3……1000]和一个出现两次的x为1到1000中的任一个数字。这样就可以计算原数组里的所有数字之和S1和等差数列[1,2,3……1000]的和S2,再计算S1与S2之差,该差就是原数组中出现两次的数字x。时间复杂度是固定的O(n)。优缺点:内存空间消耗几乎没有,但是效率要输于使用hash表的存储方式。代码如下:

  1. int fun2(const int a[])  
  2. {  
  3.   int s1=0,s2;  
  4.   s2 = 1001*1000/2;   
  5.   for(int i = 0; i<1001; i++)  
  6.     {  
  7.       s1+=a[i];  
  8.     }  
  9.   return s1-s2;  






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值