各大公司笔试面试题之数据结构与算法

题目部分转自:http://my.csdn.net/v_JULY_v 部分来自他处。

答案是本人自己编写的,可能存在bug,欢迎讨论


logic


1. 把二元查找树转变成排序的双向链表

  1. //基本思想:假设根的左右两棵子树都已经转为链表,则只需将根指向左孩子的链指向左链表的最后一个节点  
  2. //将根指向右孩子的链指向右链表的第一个节点  
  3. #include <iostream>  
  4. using namespace std;  
  5.   
  6. struct node  
  7. {  
  8.     int value;  
  9.     node *left;  
  10.     node *right;  
  11. };  
  12.   
  13. void treeToList(node *root)  
  14. {  
  15.     if(!root)  
  16.         return;  
  17.     treeToList(root->left);  
  18.     treeToList(root->right);  
  19.     node *cur;  
  20.     if(root->left)  
  21.     {  
  22.         cur = root->left;  
  23.         while(cur->right)  
  24.         {  
  25.             cur = cur->right;  
  26.         }  
  27.         root->left = cur;  
  28.         cur->right = root;  
  29.     }  
  30.     if(root->right)  
  31.     {  
  32.         cur = root->right;  
  33.         while(cur->left)  
  34.         {  
  35.             cur = cur->left;  
  36.         }  
  37.         root->right = cur;  
  38.         cur->left = root;  
  39.     }  
  40. }  
  41.   
  42. node * treeToListInterface(node *root)  
  43. {  
  44.     treeToList(root);  
  45.     node *cur = root;  
  46.     if(cur)  
  47.     {  
  48.         while(cur->left)  
  49.             cur = cur->left;  
  50.     }  
  51.     return cur;  
  52. }  
  53.   
  54. node * build_tree()  
  55. {  
  56.     int a;  
  57.     cin >> a;  
  58.     if(a == 0)  
  59.     {  
  60.         return NULL;  
  61.     }  
  62.     node *root = new node();  
  63.     root->value = a;  
  64.     root->left = build_tree();  
  65.     root->right = build_tree();  
  66.     return root;  
  67. }  
  68.   
  69. void displayList(node *head)  
  70. {  
  71.     node *cur = head;  
  72.     while(cur)  
  73.     {  
  74.         cout  << cur->value << " ";  
  75.         cur = cur->right;  
  76.     }  
  77.     cout << endl;  
  78. }  
  79.   
  80. int main()  
  81. {  
  82.     node *root = build_tree();  
  83.     root = treeToListInterface(root);  
  84.     displayList(root);  
  85.     return 0;  
  86. }  





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

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

  1. //基本思想:增加一个辅助栈,辅助栈的栈顶元素既是当前最小元素的下标。  
  2. //每次出栈时,同时对辅助栈也执行pop操作。  
  3. #include <iostream>  
  4. using namespace std;  
  5. const int N = 100;  
  6. class Stack  
  7. {  
  8. private:  
  9.     int a[N];  
  10.     int top;  
  11.     int b[N];  
  12.     int btop;  
  13. public:  
  14.     Stack():top(-1),btop(-1){}  
  15.     void push(int e){  
  16.         a[++top] = e;  
  17.         if(btop == -1)  
  18.         {  
  19.             b[++btop] = 0;  
  20.         }else  
  21.         {  
  22.             b[btop + 1] = e < a[b[btop]] ? top: b[btop];  
  23.             btop++;  
  24.         }  
  25.     }  
  26.     void pop()  
  27.     {  
  28.         --top;  
  29.         --btop;  
  30.     }  
  31.     int min()  
  32.     {  
  33.         return a[b[btop]];  
  34.     }  
  35. };  
  36.   
  37. int main()  
  38. {  
  39.     Stack test;  
  40.     test.push(1);  
  41.     cout << test.min() << endl;  
  42.     test.push(2);  
  43.     cout << test.min() << endl;  
  44.     test.push(4);  
  45.     cout << test.min() << endl;  
  46.     test.push(5);  
  47.     cout << test.min() << endl;  
  48. }  


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

  1. //基本思想:dp  
  2. //从后往前思考,从前往后写代码。  
  3. //t[i]表示包括a[i]在内的最大子数组之和  
  4. //在处理大小为i的数组时,先假设大小为i-1的数组已经处理好  
  5. //则t[i] = t[i - 1] + a[i] > a[i] ? t[i - 1] + a[i] : a[i];  
  6. #include <iostream>  
  7. using namespace std;  
  8.   
  9. const int N =100;  
  10. int MaxSumOfSubArray(int *a, int size)  
  11. {  
  12.     int t[N];  
  13.     t[0] = a[0];  
  14.     for(int i = 1; i < size; i++)  
  15.     {  
  16.         t[i] = t[i - 1] + a[i] > a[i] ? t[i - 1] + a[i] : a[i];  
  17.     }  
  18.     int max = t[0];  
  19.     for(int i = 1; i < size; i++)  
  20.     {  
  21.         max = max > t[i] ? max : t[i];  
  22.     }  
  23.     return max;  
  24. }  
  25.   
  26. int main()  
  27. {  
  28.     int a[8] = { 1, -2, 3, 10, -4, 7, 2, -5 };  
  29.     cout << MaxSumOfSubArray(a, 8);  
  30.   
  31. }  


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

};

  1. //基本思想:函数的接口、数据结构设计好了,算法也就呼之欲出了。  
  2. //需要随着回溯而改变的变量应该作为递归函数的形参,可以考虑增加辅助函数  
  3. #include <iostream>  
  4. using namespace std;  
  5. const int N = 100;  
  6. struct BinaryTreeNode // a node in the binary tree  
  7. {  
  8.     int m_nValue; // value of node  
  9.     BinaryTreeNode *m_pLeft; // left child of node  
  10.     BinaryTreeNode *m_pRight; // right child of node  
  11. };  
  12. int path[N];  
  13. int cur = 0;  
  14.   
  15. void findPathRecursively(BinaryTreeNode *root, int value ,int cur)  
  16. {  
  17.     if(!root)  
  18.         return ;  
  19.     if(!root->m_pLeft && !root->m_pLeft)  
  20.     {  
  21.         if(root->m_nValue == value)  
  22.         {  
  23.             path[cur++] = value;  
  24.             for(int i = 0; i < cur; i++)  
  25.                 cout << path[i] << " ";  
  26.             cout << endl;  
  27.         }  
  28.     }  
  29.     else  
  30.     {  
  31.         path[cur++] = root->m_nValue;  
  32.         if(root->m_pLeft)  
  33.         {  
  34.   
  35.             findPathRecursively(root->m_pLeft, value - root->m_nValue, cur);  
  36.         }  
  37.         if(root->m_pRight)  
  38.         {  
  39.   
  40.             findPathRecursively(root->m_pRight, value - root->m_nValue, cur);  
  41.         }  
  42.     }  
  43. }  
  44.   
  45. //这样设置,path[],cur不能跟着递归改变。  
  46. //所以必须使用一个辅助函数  
  47. void findPath(BinaryTreeNode *root, int value)  
  48. {  
  49.     findPathRecursively(root,value,cur);  
  50. }  
  51. BinaryTreeNode * build_tree()  
  52. {  
  53.     int a;  
  54.     cin >> a;  
  55.     if(a == 0)  
  56.     {  
  57.         return NULL;  
  58.     }  
  59.     BinaryTreeNode *root = new BinaryTreeNode();  
  60.     root->m_nValue = a;  
  61.     root->m_pLeft = build_tree();  
  62.     root->m_pRight = build_tree();  
  63.     return root;  
  64. }  
  65.   
  66. int main()  
  67. {  
  68.     BinaryTreeNode *tree = build_tree();  
  69.     findPath(tree, 10);  
  70.   
  71. }  


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

  1. //基本思想:先快排  
  2. //有更好的方法,以后有时间再写  
  3.   
  4.   
  5. #include <iostream>  
  6. #include <ctime>  
  7. using namespace std;  
  8. const int N = 10000;  
  9.   
  10. int partition(int *a, int b, int e)  
  11. {  
  12.     int i = b - 1;  
  13.        
  14.     for(int j = b; j < e; j++)  
  15.     {  
  16.         if(a[j] < a[e])  
  17.         {  
  18.             i++;  
  19.             int tem = a[i];  
  20.             a[i] = a[j];  
  21.             a[j] = tem;  
  22.         }  
  23.     }  
  24.       
  25.     int tem = a[i + 1];  
  26.     a[i + 1] = a[e];  
  27.     a[e] = tem;  
  28.     return i + 1;  
  29.       
  30. }  
  31.   
  32. void qsort(int *a, int b, int e)  
  33. {  
  34.     if(b < e)  
  35.     {  
  36.         int q = partition(a,b,e);  
  37.         qsort(a, b, q-1);  
  38.         qsort(a, q+1, e);  
  39.     }  
  40. }  
  41.   
  42. void fun(int *a, int size, int k)  
  43. {  
  44.     qsort(a, 0, size - 1);  
  45.     for(int i = 0; i < k; i++)  
  46.         cout << a[i] << " ";  
  47.     cout << endl;  
  48. }  
  49. int main()  
  50. {  
  51.     int a[] = {3,4,8,2,1};  
  52.     fun(a, 5, 2);  
  53. }  


第 6 题
转换字符串格式为:原来字符串里的字符+该字符连续出现的个数。

  1. #include <iostream>  
  2. #include <ctime>  
  3. #include <cassert>  
  4. using namespace std;  
  5. const int N = 10000;  
  6. void convertStringFormat(char *str)  
  7. {  
  8.     for(int i = 0, len = strlen(str); i < len; i++)  
  9.     {  
  10.         int count = 1;  
  11.         cout << str[i];  
  12.         while(str[i] == str[i + 1])  
  13.         {  
  14.             count ++;  
  15.             i++;  
  16.         }  
  17.         cout << count;  
  18.     }  
  19. }  
  20. int main()  
  21. {  
  22.     convertStringFormat("1233422222");  
  23.   
  24. }  


第 7 题
微软亚院之编程判断俩个链表是否相交
给出俩个单向链表的头指针,比如 h1 , h2 ,判断这俩个链表是否相交。
为了简化问题,我们假设俩个链表均不带环。

  1. //基本思想:若两链表相交,则它们最终合并为一条链表  
  2.   
  3. #include <iostream>  
  4. #include <ctime>  
  5. using namespace std;  
  6.   
  7. struct node  
  8. {  
  9.     int value;  
  10.     node *next;  
  11. };  
  12.   
  13. void displayList(node *head)  
  14. {  
  15.     node *cur = head;  
  16.     while(cur)  
  17.     {  
  18.         cout  << cur->value << " ";  
  19.         cur = cur->next;  
  20.     }  
  21.     cout << endl;  
  22. }  
  23.   
  24. bool isCross(node *h1, node *h2)  
  25. {  
  26.     node *cur1 = h1, *cur2 = h2;  
  27.     if(!h1 || !h2)  
  28.         return false;  
  29.     while(cur1->next)  
  30.         cur1 = cur1->next;  
  31.     while(cur2->next)  
  32.         cur2 = cur2->next;  
  33.     return cur1 == cur2;  
  34. }  
  35. node * make_link()  
  36. {  
  37.     srand(time(NULL));  
  38.     node *head = new node();  
  39.     node *cur = head;  
  40.     for(int i= 0; i < 10; i++)  
  41.     {  
  42.         cur->value = rand() % 10;  
  43.         cur->next = new node();  
  44.         cur = cur->next;  
  45.     }  
  46.     return head;  
  47. }  
  48.   
  49. int main()  
  50. {  
  51.     node *h1 = make_link();;  
  52.     node *h2 = new node();  
  53.     h2->value = 1;  
  54.     node *tem = h2->next = new node();  
  55.     tem->value = 2;  
  56.     /*tem->next = h1->next->next->next;*/  
  57.     tem->next = NULL;  
  58.   
  59.       
  60.     cout << isCross(h1, h2);  
  61.     return 0;  
  62. }  

第8题:

问题扩展:
1. 如果链表可能有环列 ?
2. 如果需要求出俩个链表相交的第一个节点列 ?

  1. //扩展2  
  2. //基本思想:若两链表相交,则它们最终合并为一条链表  
  3. //设两链表的长度分别为l1,l2,使指向长链表的指针先走|l1-l2|,  
  4. //然后两链表指针再一起走,它们将到时到达相交节点  
  5.   
  6. #include <iostream>  
  7. #include <ctime>  
  8. using namespace std;  
  9.   
  10. struct node  
  11. {  
  12.     int value;  
  13.     node *next;  
  14. };  
  15.   
  16. void displayList(node *head)  
  17. {  
  18.     node *cur = head;  
  19.     while(cur)  
  20.     {  
  21.         cout  << cur->value << " ";  
  22.         cur = cur->next;  
  23.     }  
  24.     cout << endl;  
  25. }  
  26.   
  27.   
  28. node *firstCrossNode(node *h1, node *h2)  
  29. {  
  30.     node *cur1 = h1, *cur2 = h2;  
  31.       
  32.     if(!h1 || !h2)  
  33.         return NULL;  
  34.     int len1 = 1, len2 = 1;  
  35.     while(cur1->next)  
  36.     {  
  37.         cur1 = cur1->next;  
  38.         len1++;  
  39.     }  
  40.     while(cur2->next)  
  41.     {  
  42.         cur2 = cur2->next;  
  43.         len2++;  
  44.     }  
  45.     if(cur1 != cur2)  
  46.         return NULL;  
  47.   
  48.     cur1 = h1;  
  49.     cur2 = h2;  
  50.     if(len1 > len2)  
  51.     {  
  52.         for(int i = 0; i < len1 - len2; i++)  
  53.         {  
  54.             cur1 = cur1->next;  
  55.         }  
  56.     }  
  57.     else  
  58.     {  
  59.         for(int i = 0; i < len2 - len1; i++)  
  60.         {  
  61.             cur2 = cur2->next;  
  62.         }  
  63.     }  
  64.     while(cur1 != cur2)  
  65.     {  
  66.         cur1 = cur1->next;  
  67.         cur2 = cur2->next;  
  68.     }  
  69.     return cur1;  
  70. }  
  71. node * make_link()  
  72. {  
  73.     srand(time(NULL));  
  74.     node *head = new node();  
  75.     node *cur = head;  
  76.     for(int i= 0; i < 10; i++)  
  77.     {  
  78.         cur->value = rand() % 10;  
  79.         cur->next = new node();  
  80.         cur = cur->next;  
  81.     }  
  82.     return head;  
  83. }  
  84.   
  85. int main()  
  86. {  
  87.     node *h1 = make_link();;  
  88.     node *h2 = new node();  
  89.     h2->value = 1;  
  90.     node *tem = h2->next = new node();  
  91.     tem->value = 2;  
  92.     tem->next = h1->next->next->next;  
  93.     /*tem->next = NULL;*/  
  94.   
  95.       
  96.     cout << firstCrossNode(h1, h2)->value;  
  97.     return 0;  
  98. }  

第9题

将一句话里的单词进行倒置,标点符号不倒换。比如“i come from shantou.” -> "santou. from com i"

  1. //基本思想:先整句逆转,再部分逆转。  
  2.   
  3. #include <iostream>  
  4. #include <ctime>  
  5. #include <cassert>  
  6. using namespace std;  
  7. const int N = 10000;  
  8. void reverse(char *str, int b, int e)  
  9. {  
  10.     int i = b, j = e;  
  11.     while(i < j)  
  12.     {  
  13.         char tem = str[i];  
  14.         str[i] = str[j];  
  15.         str[j] = tem;  
  16.         i++;  
  17.         j--;  
  18.     }  
  19. }  
  20. void reverseWordsOfSentence(char *str)  
  21. {  
  22.     reverse(str, 0, strlen(str) - 1);  
  23.     for(int i = 0, len = strlen(str); i < len; )  
  24.     {  
  25.         int b = i;  
  26.         while(str[i++] != ' ' && str[i++] != '\0')  
  27.             ;  
  28.         reverse(str, b, i - 2);  
  29.     }  
  30. }  
  31.   
  32. int main()  
  33. {  
  34.     char str[] = "I come from shantou.";  
  35.     reverseWordsOfSentence(str);  
  36.     cout << str << endl;  
  37. }  

第10题

实现strstr()函数

  1. 不想做。  


第 11 题

求二叉树中节点的最大距离 ...
如果我们把二叉树看成一个图,父子节点之间的连线看成是双向的,
我们姑且定义 " 距离 " 为两节点之间边的个数。
写一个程序,
求一棵二叉树中相距最远的两个节点之间的距离。
  1. //总结来自《微软编程之美》:  
  2. //  对于递归问题的分析,笔者有一些小小的体会:   
  3. //1. 先弄清楚递归的顺序。在递归的实现中,往往需要假设后续的调用已经完成,在此  
  4. //基础之上,才实现递归的逻辑。在该题中,我们就是假设已经把后面的长度计算出  
  5. //来了,然后继续考虑后面的逻辑;   
  6. //2. 分析清楚递归体的逻辑,然后写出来。比如在上面的问题中,递归体的逻辑就是如  
  7. //何计算两边最长的距离;   
  8. //3. 考虑清楚递归退出的边界条件。也就说,哪些地方应该写return。   
  9. //注意到以上 3 点,在面对递归问题的时候,我们将总是有章可循。   
  10. #include<iostream>  
  11. using namespace std;  
  12. struct Node  
  13. {  
  14.     Node *left;  
  15.     Node *right;  
  16.     int nMaxLeft;  
  17.     int nMaxRight;  
  18.     //char chValue;  
  19. };  
  20.   
  21. int nMaxLen = 0;  
  22.   
  23. int maxNode(Node *tree)  
  24. {  
  25.     return tree->nMaxLeft > tree->nMaxRight ?  
  26.         tree->nMaxLeft : tree->nMaxRight;  
  27. }  
  28.   
  29. void find(Node *tree)  
  30. {  
  31.     if(tree->left)  
  32.     {  
  33.         find(tree->left);  
  34.     }else  
  35.     {  
  36.         tree->nMaxLeft = 0;  
  37.     }  
  38.     if(tree->right)  
  39.     {  
  40.         find(tree->right);  
  41.     }else  
  42.     {  
  43.         tree->nMaxRight = 0;  
  44.     }  
  45.     tree->nMaxLeft = maxNode(tree->left) + 1;  
  46.     tree->nMaxRight = maxNode(tree->right) + 1;  
  47.     nMaxLen = nMaxLen > tree->nMaxLeft + tree->nMaxRight ? nMaxLen : tree->nMaxLeft + tree->nMaxRight;  
  48.   
  49. }  


第 13 题:

题目:输入一个单向链表,输出该链表中倒数第 k 个结点。链表的倒数第 0 个结点为链表的尾指针。

  1. 已经做过。  


第 14 题:
题目:输入一个已经按升序排序过的数组和一个数字,
在数组中查找两个数,使得它们的和正好是输入的那个数字。
要求时间复杂度是 O(n) 。如果有多对数字的和等于输入的数字,输出任意一对即可。
例如输入数组 1 、 2 、 4 、 7 、 11 、 15 和数字 15 。由于 4+11=15 ,因此输出 4 和 11 。

  1. 已经做过。  


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

例如输入
8
/ \
6 10

/\ /\
5 7 9 11
输出:
8
/ \
10 6
/\ /\
11 9 7 5


  1. //基本思想:假设根的左右两棵子树都已经镜像转换好了,则只需改变根的左右链的指向互换就可以了  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. struct node  
  6. {  
  7.     int value;  
  8.     node *left;  
  9.     node *right;  
  10. };  
  11.   
  12. void display(node *root)  
  13. {  
  14.     if(!root)  
  15.         return ;  
  16.     display(root->left);  
  17.     cout << root->value << " ";  
  18.     display(root->right);  
  19. }  
  20.   
  21. node * build_tree()  
  22. {  
  23.     int a;  
  24.     cin >> a;  
  25.     if(a == 0)  
  26.     {  
  27.         return NULL;  
  28.     }  
  29.     node *root = new node();  
  30.     root->value = a;  
  31.     root->left = build_tree();  
  32.     root->right = build_tree();  
  33.     return root;  
  34. }  
  35.   
  36. void treeImage(node *root)  
  37. {  
  38.     if(!root)  
  39.         return;  
  40.     treeImage(root->left);  
  41.     treeImage(root->right);  
  42.     node *tem = root->left;  
  43.     root->left = root->right;  
  44.     root->right = tem;  
  45. }  
  46.   
  47. int main()  
  48. {  
  49.     node *root = build_tree();  
  50.     treeImage(root);  
  51.     display(root);  
  52.     return 0;  
  53. }  

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

输出 8 6 10 5 7 9 11 。


  1. //基本思想:BFS  
  2. #include <iostream>  
  3. #include <ctime>  
  4. #include <queue>  
  5. using namespace std;  
  6.   
  7. struct node  
  8. {  
  9.     int value;  
  10.     node *left;  
  11.     node *right;  
  12.   
  13. };  
  14.   
  15. node * build_tree()  
  16. {  
  17.     int a;  
  18.     cin >> a;  
  19.     if(a == 0)  
  20.     {  
  21.         return NULL;  
  22.     }  
  23.     node *root = new node();  
  24.     root->value = a;  
  25.     root->left = build_tree();  
  26.     root->right = build_tree();  
  27.     return root;  
  28. }  
  29. void print(node *root)  
  30. {  
  31.     queue<node *> toPrint;  
  32.     if(root)  
  33.     {  
  34.         toPrint.push(root);  
  35.         while(!toPrint.empty())  
  36.         {  
  37.             node *tem = toPrint.front();  
  38.             toPrint.pop();  
  39.             cout << tem->value <<  " ";  
  40.             if(tem->left)  
  41.             {  
  42.                 toPrint.push(tem->left);  
  43.             }  
  44.             if(tem->right)  
  45.             {  
  46.                 toPrint.push(tem->right);  
  47.             }  
  48.         }  
  49.     }  
  50. }  
  51.   
  52. int main()  
  53. {  
  54.     node *root = build_tree();  
  55.     print(root);  
  56.     return 0;  
  57. }  



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

分析:这道题是 2006 年 google 的一道笔试题。

  1. //注:此题解法参与了July的解法  
  2. //基本思想:涉及到出现次数的可以考虑一下用hash表  
  3. #include <iostream>  
  4. using namespace std;  
  5.   
  6. char findFirstSingle(char *str)  
  7. {  
  8.     int a[255];  
  9.     memset(str,0,sizeof(a));  
  10.     char *p = str;  
  11.     while(*p != '\0')  
  12.     {  
  13.         a[*p]++;  
  14.         p++;  
  15.     }  
  16.     p = str;  
  17.     while(*p != '\0')  
  18.     {  
  19.         if(a[*p] == 1);  
  20.         return *p;  
  21.     }  
  22.     return '\0';  
  23. }  




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

  1. //基本思想:用循环表模拟  
  2. //网上有比较牛的算法,但有点难理解  
  3. #include <iostream>  
  4. #include <ctime>  
  5. #include <queue>  
  6. using namespace std;  
  7.   
  8. struct node  
  9. {  
  10.     int value;  
  11.     node *next;  
  12.   
  13. };  
  14.   
  15. node* theLastGuy(int n, int m)  
  16. {  
  17.     if(n == 0)  
  18.         return NULL;  
  19.     node *head = new node();  
  20.     head->value = 0;  
  21.     node *cur = head;  
  22.     for(int i= 1; i < n; i++)  
  23.     {  
  24.         cur->next = new node();  
  25.         cur = cur->next;  
  26.         cur->value = i;  
  27.     }  
  28.     cur->next = head;  
  29.     cur = head;  
  30.     int s;  
  31.     while(cur->next)  
  32.     {  
  33.         s = m - 1;  
  34.         while(s--)  
  35.         {  
  36.             cur = cur->next;  
  37.         }  
  38.         node *tem = cur->next;  
  39.         cur->next = cur->next->next;  
  40.         tem->next = NULL;  
  41.         delete tem;  
  42.   
  43.     }  
  44. }  
  45.   
  46. int main()  
  47. {  
  48.     cout << "input n and m" << endl;  
  49.     int n, m;  
  50.     cin >> n >> m;  
  51.     theLastGuy(n, m);  
  52.     return 0;  
  53. }  



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

  1. //基本思想:‘3’- '0' = 3  
  2. #include <iostream>  
  3. using namespace std;  
  4.   
  5. void convert(char *a)  
  6. {  
  7.     for(int i = 0; i < strlen(a); i++)  
  8.     {  
  9.         cout << a[i] - '0';  
  10.     }  
  11. }  
  12. int main()  
  13. {  
  14.     char *a = "345";  
  15.     convert(a);  
  16.     return 0;  
  17. }  

第 21 题
2010 年中兴面试题
编程求解:
输入两个整数 n 和 m ,从数列 1 , 2 , 3.......n 中随意取几个数
使其和等于 m , 要求将其中所有的可能组合列出来 .

  1. //基本思想:组合数学,用母函数解即可。  
  2. //母函数:将离散的数列变成对应连续的幂数,幂指数为对应的数列项的值  
  3. //母函数的G(x)=  (1+x+x^2+x^3+x^4+x^5+....)*(1+x^2+x^4+x^6+x^8+x^10+....)*  
  4.   
  5. (1+x^3+x^6+x^9+x^12....).....  
  6. //其中第一项表示的1表示第一个数列取一次,x表示取两次,...其它的数列也一样。  
  7. //实现时,用数组下标表示幂指数,对应的值表示该幂数的系数,然后对多项式展开就可以了。  
  8. //只要计算到下标为m的数组值就可以了,注意循环变量每次的增量。  
  9. #include <iostream>  
  10. #include <ctime>  
  11. using namespace std;  
  12. const int N = 10000;  
  13. int c1[N], c2[N];  
  14. int combination(int n, int m)  
  15. {  
  16.     int len = 0;  
  17.     for(int i = 1; i <= n ; i++)  
  18.         len += i;  
  19.     if(m > len)  
  20.         return 0;  
  21.     for(int i = 0; i <= m; i ++)  
  22.     {  
  23.         c1[i] = c2[i] = 0;  
  24.     }  
  25.     for(int i = 0; i <= 1; i++)  
  26.     {  
  27.         c1[i] = 1;  
  28.     }  
  29.     for(int i = 1; i < n ; i++)  
  30.         for(int j = 0; j <= m; j++)  
  31.             for(int k = 0;k <= i + 1 && k + j <= m; k += i+1)  
  32.             {  
  33.                 c2[j + k] += c1[j];  
  34.             }  
  35.     for(int i = 0; i <= m; i++)  
  36.     {  
  37.         c1[i] = c2[i];  
  38.         c2[i] = 0;  
  39.     }  
  40.     return c1[m];  
  41. }  
  42. int main()  
  43. {  
  44.     int n , m;  
  45.     cin >> n >> m;  
  46.     cout << combination(n,m);  
  47. }  


第 25 题:
写一个函数 , 它的原形是 int continumax(char *outputstr,char *intputstr)
功能:
在字符串中找出连续最长的数字串,并把这个串的长度返回,
并把这个最长数字串付给其中一个函数参数 outputstr 所指内存。
例如: "abcd12345ed125ss123456789" 的首地址传给 intputstr 后,函数将返回 9 ,

outputstr 所指的值为 123456789

  1. //基本思想:dp  
  2. #include <iostream>  
  3. #include <ctime>  
  4. using namespace std;  
  5. const int N = 10000;  
  6. int a[N];  
  7. int maxsub(char *str)  
  8. {  
  9.     if(!str)  
  10.         return 0;  
  11.     memset(a, 0, sizeof(a));  
  12.     if(str[0] >= '0' && str[0] <= '9')  
  13.         a[0] = 1;  
  14.     else  
  15.         a[0] = 0;  
  16.     int len = strlen(str);  
  17.     for(int i = 1; i < len; i++)  
  18.     {  
  19.         a[i] = str[i] >= 'a' && str[i] <= 'z' ? 0 : a[i - 1] + 1;  
  20.     }  
  21.     int max = 0;  
  22.     for(int i = 0; i < len; i++)  
  23.     {  
  24.         max = max > a[i] ? max : a[i];  
  25.     }  
  26.     return max;  
  27. }  
  28.   
  29. int main()  
  30. {  
  31.     char *str = "ab12ab1234a";  
  32.     cout << maxsub(str);  
  33. }   

26. 左旋转字符串
题目:
定义字符串的左旋转操作:把字符串前面的若干个字符移动到字符串的尾部。
如把字符串 abcdef 左旋转 2 位得到字符串 cdefab 。请实现字符串左旋转的函数。

要求时间对长度为 n 的字符串操作的复杂度为 O(n) ,辅助内存为 O(1) 。

  1. //基本思想:ad-hoc  
  2. #include <iostream>  
  3. #include <ctime>  
  4. using namespace std;  
  5. const int N = 10000;  
  6.   
  7. void reverse(char *str, int b, int e)  
  8. {  
  9.     int i = b, j = e;  
  10.     while(i < j)  
  11.     {  
  12.         char tem = str[i];  
  13.         str[i] = str[j];  
  14.         str[j] = tem;  
  15.         i++;  
  16.         j--;  
  17.     }  
  18. }  
  19. void shift(char *str, int n)  
  20. {  
  21.     reverse(str, 0, strlen(str) - 1);  
  22.     reverse(str, 0, strlen(str) - 1 - n);  
  23.     reverse(str, strlen(str) - n, strlen(str) - 1);  
  24. }  
  25.   
  26. int main()  
  27. {  
  28.     char str[] = "abcde";  
  29.     shift(str, 2);  
  30.     cout << str << endl;  
  31. }  

27. 跳台阶问题
题目:一个台阶总共有 n 级,如果一次可以跳 1 级,也可以跳 2 级。
求总共有多少总跳法,并分析算法的时间复杂度。
这道题最近经常出现,包括 MicroStrategy 等比较重视算法的公司
都曾先后选用过个这道题作为面试题或者笔试题。
  1. //基本思想:dp。  
  2. //设a[i]为第i阶的跳法总数。从第i-1阶和第i-2阶可以跳到第i阶  
  3. //所以a[i] = a[i - 2] + a[i - 1];  
  4. #include <iostream>  
  5. #include <ctime>  
  6. using namespace std;  
  7. const int N = 10000;  
  8.   
  9. int jump(int n)  
  10. {  
  11.     int a[N];  
  12.     a[1] = 1;  
  13.     a[2] = 2;  
  14.     for(int i = 3; i <= n; i++)  
  15.     {  
  16.         a[i] = a[i - 2] + a[i - 1];  
  17.     }  
  18.     return a[n];  
  19. }  
  20.   
  21. int main()  
  22. {  
  23.     int n;  
  24.     while(cin >> n)  
  25.     {  
  26.         cout << jump(n) << endl;  
  27.     }  
  28.     return 0;  
  29. }  
28. 整数的二进制表示中 1 的个数
题目:输入一个整数,求该整数的二进制表达中有多少个 1 。
例如输入 10 ,由于其二进制表示为 1010 ,有两个 1 ,因此输出 2 。
分析:
这是一道很基本的考查位运算的面试题。
包括微软在内的很多公司都曾采用过这道题。
  1. //基本思想:xxxxxx10000 & (xxxxxx10000-1) = xxxxxx00000  
  2. //参考了july的方法。  
  3.   
  4. #include <iostream>  
  5. #include <ctime>  
  6. using namespace std;  
  7. const int N = 10000;  
  8.   
  9. int binary(int n)  
  10. {  
  11.     int count = 0;  
  12.     while(n)  
  13.     {  
  14.         n = n & (n - 1);  
  15.         count++;  
  16.     }  
  17.     return count;  
  18. }  
  19.   
  20. int main()  
  21. {  
  22.     cout << binary(10) << endl;  
  23. }  

29. 栈的 push 、 pop 序列
题目:输入两个整数序列。其中一个序列表示栈的 push 顺序,
判断另一个序列有没有可能是对应的 pop 顺序。
为了简单起见,我们假设 push 序列的任意两个整数都是不相等的。
比如输入的 push 序列是 1 、 2 、 3 、 4 、 5 ,那么 4 、 5 、 3 、 2 、 1 就有可能是一个 pop 系列。
因为可以有如下的 push 和 pop 序列:
push 1 , push 2 , push 3 , push 4 , pop , push 5 , pop , pop , pop , pop ,
这样得到的 pop 序列就是 4 、 5 、 3 、 2 、 1 。
但序列 4 、 3 、 5 、 1 、 2 就不可能是 push 序列 1 、 2 、 3 、 4 、 5 的 pop 序列。
  1. //基本思想:ad-hoc  
  2. //模拟  
  3.   
  4. #include <iostream>  
  5. #include <ctime>  
  6. using namespace std;  
  7. const int N = 10000;  
  8.   
  9. int stack[N];  
  10. int top = -1;  
  11.   
  12. bool fun(int *push, int *pop, int n)  
  13. {  
  14.     int i = 0, j = 0;  
  15.     for(int i= 0; i < n; i++)  
  16.     {  
  17.         if(push[i] == pop[j])  
  18.             j++;  
  19.         else  
  20.             stack[++top] = push[i];  
  21.     }  
  22.     while(top >= 0)  
  23.     {  
  24.         if(stack[top--] != pop[j++])  
  25.             return false;  
  26.     }  
  27.     return true;  
  28. }  
  29. int main()  
  30. {  
  31.     int push[] = {1,2,3,4,5};  
  32.     int pop[] = {4,3,5,1,2};  
  33.     cout << fun(push, pop, 5);  
  34. }  







43. 递归和非递归俩种方法实现二叉树的前序遍历。

  1. //二叉树的非递归深度遍历  
  2. //基本思想:用栈,循环 模拟递归遍历的操作  
  3. //如果存在左节点,则一直将左节点压入栈,没有才压右节点  
  4. #include <iostream>  
  5. #include <stack>  
  6. using namespace std;  
  7.   
  8. struct node  
  9. {  
  10.     int value;  
  11.     node *left;  
  12.     node *right;  
  13. };  
  14.   
  15. node* build_tree()  
  16. {  
  17.     int a;  
  18.     cin >> a;  
  19.     if(a == 0)  
  20.     {  
  21.         return NULL;  
  22.     }  
  23.     node *root = new node();  
  24.     root->value = a;  
  25.     root->left = build_tree();  
  26.     root->right = build_tree();  
  27.     return root;  
  28. }   
  29. void traverse(node *root)  
  30. {  
  31.     stack<node *> backtrack;  
  32.     while(root || !backtrack.empty())  
  33.     {  
  34.         if(root)  
  35.         {  
  36.             cout << root->value;  
  37.             backtrack.push(root);  
  38.             root = root->left;  
  39.         }else  
  40.         {  
  41.             root = backtrack.top();  
  42.             backtrack.pop();  
  43.             root = root->right;  
  44.         }  
  45.     }  
  46. }  
  47. int main()  
  48. {  
  49.     node *root = build_tree();  
  50.     traverse(root);  
  51.     return 0;  
  52. }  

整数字符串转化

  1. //整数字符串转化  
  2.   
  3.   
  4. #include <iostream>  
  5. #include <ctime>  
  6. using namespace std;  
  7. const int N = 10000;  
  8.   
  9. void myItoa(int n)  
  10. {  
  11.     char str[N];  
  12.     int i = 0;  
  13.     while(n)  
  14.     {  
  15.         str[i++] = n % 10 + '0';  
  16.         n = n / 10;  
  17.     }  
  18.     int k = 0, j = i -1;  
  19.     while(k < j)  
  20.     {  
  21.         swap(str[k],str[j]);  
  22.         k++;  
  23.         j--;  
  24.     }  
  25.     str[i] = '\0';  
  26.     cout << str << endl;  
  27. }  
  28.   
  29. int main()  
  30. {  
  31.     myItoa(10);  
  32. }  

字符串整数转化
  1. #include <iostream>  
  2. #include <ctime>  
  3. using namespace std;  
  4. const int N = 10000;  
  5.   
  6. void myAtoi(char *a)  
  7. {  
  8.     int sum = 0;  
  9.     int len = strlen(a);  
  10.     for(int i = len - 1, j = 1; i >= 0; i--,j *= 10)  
  11.     {  
  12.         sum += (a[i] - '0') * j;  
  13.     }  
  14.     cout << sum << endl;  
  15. }  
  16.   
  17. int main()  
  18. {  
  19.     myAtoi("1020");  
  20. }  

字符串拷贝函数
  1. #include <iostream>  
  2. #include <ctime>  
  3. #include <cassert>  
  4. using namespace std;  
  5. const int N = 10000;  
  6.   
  7. char *strcpy(char *dest, char *src)  
  8. {  
  9.     char *cp = dest;  
  10.     while( *cp++ = *src++)  
  11.         ;  
  12.     return dest;  
  13. }  
  14.   
  15. int main()  
  16. {  
  17.     char test[] = "123";  
  18.     char dest[100];  
  19.     cout << strcpy(dest, test);  
  20.   
  21. }  

字符串循环右移n位

  1. //先整体反转,再局部反转  
  2.   
  3. #include <iostream>  
  4. #include <ctime>  
  5. #include <cassert>  
  6. using namespace std;  
  7. const int N = 10000;  
  8. void rev(char *p, int b, int e)  
  9. {  
  10.     while(b < e)  
  11.     {  
  12.         swap(p[b++],p[e--]);  
  13.     }  
  14. }  
  15.   
  16. void shift(char *p, int n)  
  17. {  
  18.     rev(p, 0, strlen(p) - 1);  
  19.     rev(p, 0, n - 1);  
  20.     rev(p, n,  strlen(p) - 1);  
  21. }  
  22.   
  23. int main()  
  24. {  
  25.     char a[] = "abcdefghi";  
  26.     shift(a,2);  
  27.     cout << a << endl;  
  28.   
  29. }  


最长公共子序列

  1. //dp  
  2. c[i, j] =            0         i == 0 或 j == 0  
  3.   
  4. c[i, j] =            c[ i - 1, j - 1] + 1           i, j >0 && xi == yj  
  5.   
  6. c[i, j] =            max( c[ i - 1, j ], c[ i, j - 1 ] )                i, j>0 && i != j  




输入一字符串,找出其中出现的相同且长度最长的字符串

  1. //转自网上,用了O(n^3)的方法  
  2. //ps:正规解法应该用字典树  
  3. #include "iostream"  
  4. #include "string"  
  5. using namespace std;  
  6.    
  7.    
  8. int main()   
  9. {  
  10.     string strInput;  
  11.     cout << "Input a string: " << endl;  
  12.     cin >> strInput;  
  13.     string strTemp;  
  14.     for (size_t i = strInput.length() - 1; i > 1; i--)  
  15.     {  
  16.         for (size_t j = 0; j < strInput.length(); j++)  
  17.         {  
  18.             if ((i + j) <= strInput.length())  
  19.             {  
  20.                 size_t szForw = 0;  
  21.                 size_t szBacw = 0;  
  22.                 strTemp = strInput.substr(j, i);  
  23.                 szForw = strInput.find(strTemp);  
  24.                 szBacw = strInput.rfind(strTemp);  
  25.                 if (szBacw != szForw)  
  26.                 {  
  27.                     cout << strTemp << " " << szForw + 1 << endl;  
  28.                     return 0;  
  29.                 }  
  30.             }  
  31.         }  
  32.     }  
  33.    
  34.     return 1;  
  35. }  



校门外的树

某校大门外长度为L的马路上有一排树,每两棵相邻的树之间的间隔都是1。我们可以把马路看成一个数轴,马路的一端在数轴0的位置,另一端在L的位置;数轴上的每个整数点,即012,……,L,都种有一棵树。

由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。

  1. //基本思想:位图法  
  2.   
  3. #include <iostream>  
  4. #include <bitset>  
  5. using namespace std;  
  6.   
  7. const int N = 10000;  
  8. struct Segment  
  9. {  
  10.     int start;  
  11.     int end;  
  12. };  
  13.   
  14. int coverage(Segment *segments, int n)  
  15. {  
  16.     bool c[N];  
  17.     memset(c, 0, sizeof(c));  
  18.     int end = 0;  
  19.     for(int i = 0; i < n; i++)  
  20.     {  
  21.         for(int j = segments[i].start; j < segments[i].end; j++)  
  22.         {  
  23.             c[j] = true;  
  24.         }  
  25.         if(segments[i].end > end)  
  26.             end = segments[i].end;  
  27.     }  
  28.     int max = 0;  
  29.     for(int i= 0; i < end; i++)  
  30.     {  
  31.         int count = 1;  
  32.         if(c[i] == true)  
  33.         {  
  34.             while(c[++i] == true)  
  35.             {  
  36.                 count++;  
  37.             }  
  38.         }  
  39.         if(count > max)  
  40.             max= count;  
  41.     }  
  42.     return max;  
  43. };  
  44.   
  45. int main()  
  46. {  
  47.     Segment s1;  
  48.     s1.start = 0;  
  49.     s1.end = 5;  
  50.     Segment s2;  
  51.     s2.start = 6;  
  52.     s2.end = 7;  
  53.     Segment ss[] = {s1,s2};  
  54.     cout << coverage(ss, 2);  
  55. }  


Suppose there  is a two-dimension array  a[1 .. 60,1 .. 70] with 60 rows and 70 
columns ,whose main order is the column order(以列序为主序). If the base address is 10000 
and each element occupies two storage unit, then the storage address of a[32,58] is ( ). (无第
0 行第 0 列元素) 
A)14454      B)16904      C)16902      D) None of above 


Sorting the  sequence (25,84,21,47,15,27,68,35,20) , the sequence changes  are 
(20,15,21,25,47,27,68,35,84),(15,20,21,25,35,27,47,68,84),(15,20,21,25,27,35,47,68,84). 
Which kind of sorting algorithm we used ? ( ) 
 A) Selection sort    B) shell sort    C) merge sort    D) quick sort 


怎样编写一个程序,把一个有序整数数组放到二叉树中?

  1. #include <iostream>  
  2. using namespace std;  
  3.   
  4. struct Node  
  5. {  
  6.     int value;  
  7.     Node *left;  
  8.     Node *right;  
  9. };  
  10. void binaryTree(Node *&root, int a[], int n)  
  11. {  
  12.     if(n > 0)  
  13.     {  
  14.         root = new Node();   
  15.         root->value = a[n/2];  
  16.         binaryTree(root->left , a,  n/2 );  
  17.         binaryTree(root->right, a + n/2 + 1, n - n/2 - 1);  
  18.     }else  
  19.     {  
  20.         root = NULL;  
  21.     }  
  22. }  
  23. void display(Node *root)  
  24. {  
  25.     if(!root)  
  26.         return ;  
  27.     display(root->left);  
  28.     cout << root->value << " ";  
  29.     display(root->right);  
  30. }  
  31. int main()  
  32. {  
  33.     int a[] = {1,2,3,4,5};  
  34.     Node *root = NULL;  
  35.     binaryTree(root, a, 5);  
  36.     display(root);  
  37. }  

给出一个函数来输出一个字符串的所有排列。

  1. //基本思想:递归  
  2. //从要全排列的字符串中取出一个字符,加入到prefix字符串中  
  3. //然后递归  
  4. //当要全排列的字符串为空时,就可以输出prefix字符串了。  
  5. #include <iostream>  
  6. #include <string>  
  7. using namespace std;  
  8.    
  9. void permut(string pre, string toPermut)  
  10. {  
  11.     if(toPermut.length() == 0)  
  12.         cout << pre << endl;  
  13.     else  
  14.     {  
  15.         for(int i = 0; i < toPermut.length(); i++)  
  16.         {  
  17.             permut(pre + toPermut[i], toPermut.substr(0,i)+toPermut.substr(i+1,toPermut.length()));  
  18.         }  
  19.     }  
  20. }  
  21. void print(string str)  
  22. {  
  23.     permut("",str);  
  24. }  
  25.    
  26. int main(void)  
  27. {  
  28.     print("abc");  
  29.     return 0;  
  30. }  

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

  1. //基本思想:快慢指针  
  2. #include <iostream>  
  3. #include <string>  
  4. using namespace std;  
  5.   
  6. struct Node  
  7. {  
  8.     int value;  
  9.     Node *next;  
  10. };  
  11. bool hasCircle(Node *head)  
  12. {  
  13.     Node *fast;  
  14.     Node *slow;  
  15.     fast = slow = head;  
  16.     if(head == NULL  || head->next == NULL)  
  17.         return false;  
  18.     do  
  19.     {  
  20.         fast = fast->next;  
  21.         fast = fast->next;  
  22.         slow = slow->next;  
  23.     }while(fast != NULL && fast != slow);  
  24.     return !(fast == NULL);  
  25. }  
  26.    
  27. int main(void)  
  28. {  
  29.     Node *head = new Node();  
  30.     head->value = 1;  
  31.     Node *tem = head->next = new Node();  
  32.     tem->value = 2;  
  33.     tem->next = head;  
  34.     cout << hasCircle(head);  
  35.     return 0;  
  36. }  

给出一个单链表,不知道结点N的值,怎样只遍历一次就可以求出中间结点,写出算法。

  1. //基本思路:快慢指针。  
  2. #include <iostream>  
  3. #include <ctime>  
  4. using namespace std;  
  5. struct Node  
  6. {  
  7.     int value;  
  8.     Node *next;  
  9. };  
  10. int middle(Node *head)  
  11. {  
  12.     Node *slow, *fast;  
  13.     slow = fast = head;  
  14.     while(fast && fast->next)  
  15.     {  
  16.         fast = fast->next->next;  
  17.         slow = slow->next;  
  18.     }  
  19.     return slow->value;  
  20. }  



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值