Chinaunix首页 | 论坛 | 博客
  • 博客访问: 192651
  • 博文数量: 27
  • 博客积分: 725
  • 博客等级: 上士
  • 技术积分: 347
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-04 09:01
文章分类

全部博文(27)

文章存档

2012年(15)

2011年(12)

分类: C/C++

2012-04-23 09:16:29

最近一段时间因为要准备微软面试,所以看了不少资料,也遇到不少挺有意思的题目,与大家分享一下,下面贴出的所有代码,思路不一定是自己原创的,但是代码基本都是按照自己的理解重写的,并且经过编译运行的。暂时只贴出这些,以后还会继续贴出更多,如果有任何问题,欢迎交流哈!
 
1. 输入一个二元查找树,将该二元查找树转换成一个排序的双向链表,要求不能创建任何新的节点,只调整指针的指向。

  1. static tree_t *
  2. _tree_to_list(tree_t *root, tree_t *last)
  3. {
  4.     if (root == NULL)
  5.         return last;

  6.     if ((last = _tree_to_list(root->left, last)) != NULL)
  7.         last->right = root;
  8.     
  9.     root->left = last;

  10.     return _tree_to_list(root->right, root);
  11. }

  12. static tree_t *
  13. tree_to_list(tree_t *root)
  14. {
  15.     tree_t *last = _tree_to_list(root, NULL);
  16.     for ( ; last->left; last = last->left);
  17.     return last;
  18. }
 
2. 设计包含 max 函数的栈,定义栈的数据结构,假设栈中元素都是非负整数,要求添加一个 max 函数,能够得到栈的最大元素,要求函数 max , push 以及 pop 的时间复杂度都是O(1).

  1. struct stack {
  2.     int        *array;
  3.     int        *link;
  4.     int         size;
  5.     int         top;
  6.     int         maxidx;
  7. };
  8. typedef struct stack stack_t;

  9. static stack_t *
  10. stack_new(int n)
  11. {
  12.     stack_t *stack = calloc(1, sizeof *stack);
  13.     stack->array = calloc(n, sizeof(int));
  14.     stack->link = calloc(n, sizeof(int));
  15.     stack->size = n;
  16.     stack->top = 0;
  17.     stack->maxidx = -1;
  18.     return stack;
  19. }

  20. static int
  21. stack_empty(stack_t *s)
  22. {
  23.     return s->top <= 0;
  24. }

  25. static int
  26. stack_full(stack_t *s)
  27. {
  28.     return s->top >= s->size;
  29. }

  30. static int
  31. stack_max(stack_t *s)
  32. {
  33.     if (s->maxidx == -1)
  34.         return    -1;
  35.     else
  36.         return s->array[s->maxidx];
  37. }

  38. static void
  39. stack_push(stack_t *s, int n)
  40. {
  41.     if (stack_full(s))
  42.         return;

  43.     s->array[s->top] = n;

  44.     if (n > stack_max(s)) {
  45.         s->link[s->top] = s->maxidx;
  46.         s->maxidx = s->top;
  47.     }
  48.     else {
  49.         s->link[s->top] = -1;
  50.     }

  51.     s->top++;
  52. }

  53. static int
  54. stack_pop(stack_t *s)
  55. {
  56.     int     n;

  57.     if (stack_empty(s))
  58.         return -1;

  59.     n = s->array[--s->top];
  60.     s->array[s->top] = 0;
  61.     
  62.     if (s->maxidx == s->top)
  63.         s->maxidx = s->link[s->top];
  64.     
  65.     return n;
  66. }
 
3. 给定一个数组,元素为正负整数都可能,求其子数组的最大和。

  1. static int
  2. max_sum(int arr[], int n)
  3. {
  4.     int sum = 0, max = INT_MIN, i;
  5.     for (i = 0; i < n; i++) {

  6.         if (sum < 0)
  7.             sum = arr[i];
  8.         else
  9.             sum += arr[i];
  10.         
  11.         if (sum > max)
  12.             max = sum;
  13.     }

  14.     return max;
  15. }
 
4. 输入一个整数和一颗二元树,从树的根节点开始往下访问一直到叶节点所经过的所有节点形成一条路径
找出其各节点的和与输入整数相等的所有路径

  1. static void
  2. helper(tree_t *root, int sum)
  3. {
  4.     stack_push(s, root->n);
  5.     
  6.     sum -= root->n;
  7.     
  8.     if (sum == 0) {
  9.         stack_show(s);
  10.         goto done;
  11.     }

  12.     if (root->left != NULL)
  13.         helper(root->left, sum);
  14.     if (root->right != NULL)
  15.         helper(root->right, sum);

  16. done :
  17.     stack_pop(s);
  18.     sum += root->n;
  19. }
 
5. 输入n个整数,输出其中最大的k个

  1. static heap_t *h;

  2. static void
  3. heap_choose(int arr[], int n, int k)
  4. {
  5.     h = heap_init(k);

  6.     int i;
  7.     for (i = 0; i < n; i++) {
  8.         if (i < k) {
  9.             heap_insert(h, arr[i]);
  10.         } else {
  11.             if (arr[i] > heap_min(h)) {
  12.                 heap_delete(h);
  13.                 heap_insert(h, arr[i]);
  14.             }
  15.         }
  16.     }
  17. }
 
6. 输入一个整数数组,判断该数组是不是某二元查找树的后序遍历的结果

  1. #if 0
  2. 即数组最后一个为根,由该根可将数组分为两部分,左边即为左子树,右边为右子树,
  3. 先遍历数组直到遇到一个元素大于根,则可认为该点为分界,左边为左子树,右边为
  4. 右子树,继续遍历数组,倘若发现右边有元素小于根,说明出错,否则递归即可
  5. #endif

  6. static int
  7. is_post_order_result(int arr[], int n)
  8. {
  9.     int i, j;

  10.     if (n == 0 || n == 1)
  11.         return 1;

  12.     int head = arr[n - 1];
  13.     for (i = 0; arr[i] < head; i++) ;
  14.     for (j = i; j < n; j++)
  15.         if (arr[j] < head)
  16.             return 0;
  17.     
  18.     return is_post_order_result(arr, i)
  19.         && is_post_order_result(&arr[i], n - i - 1);

  20. }
 
7. 求一颗二叉树中相距最远的两个节点之间的距离

  1. static int
  2. helper(tree_t *root, int *depth)
  3. {
  4.     if (root == NULL) {
  5.         *depth = 0;
  6.         return 0;
  7.     }

  8.     int ld, rd;
  9.     int maxleft = helper(root->left, &ld);
  10.     int maxright = helper(root->right, &rd);
  11.     
  12.     *depth = MAX(ld, rd) + 1;
  13.     
  14.     return MAX3(maxleft, maxright, ld + rd);
  15. }
 
8. 求 1 + 2 + 3 + ... + n ,要求不能用乘除,循环, if/else, switch/case 及A ?B :C等语句

  1. typedef int (*func)(int);

  2. static int nofunc(int n);
  3. static int yesfunc(int n);

  4. func dispatch[] = {yesfunc, nofunc};

  5. static int nofunc(int n) {return 0;}

  6. static int range;

  7. static int
  8. yesfunc(int n)
  9. {
  10.     return n + dispatch[n / range](n + 1);
  11. }
还有一种方法,更简洁一些

  1. static int
  2. sum(int n)
  3. {
  4.     int val = 0;
  5.     (void) (n > 0 && (val = n + sum(n - 1)));
  6.     return val;
  7. }
再举个类似的例子,如果要你依序打印出从 1 到 10000 的所有整数,也按同样的要求,你该如何做
  1. int main(int i)
  2. {
  3.     printf("%d ", i);
  4.     (main + (exit - main) * (i / 10000))(i + 1);
  5.     return 0;
  6. }
注意,如果编译有问题的话就给后面两个相减的函数地址都强制转换成int或char *什么的,还有运行时不用跟任何命令行参数,所以 i 的起始值就是 1。

9. 输入一颗二元查找树,将该树转换为它的镜像,即在转换后的二元查找树中,左子树的节点都大于右子树的节点,用递归和非递归两种方法完成树的镜像转换

  1. static void
  2. tree_mirror_recursive(tree_t *root)
  3. {
  4.     if (root) {
  5.         tree_mirror_recursive(root->left);
  6.         tree_mirror_recursive(root->right);
  7.         swap(root->left, root->right);
  8.     }
  9. }

  10. static void
  11. tree_mirror_nonrecursive(tree_t *root)
  12. {
  13.     stack_t *s = stack_init();
  14.     stack_push(s, root);
  15.     while (!stack_empty(s)) {
  16.         tree_t *p = stack_pop(s);
  17.         swap(p->left, p->right);
  18.         if (p->left != NULL)
  19.             stack_push(s, p->left);
  20.         if (p->right != NULL)
  21.             stack_push(s, p->right);
  22.     }
  23. }

10. 输入一颗二元树,分层遍历,同一层中按照从左往右的顺序打印,给出递归和非递归方法

  1. static int
  2. _tree_show_levelorder_recursive(tree_t *root, int depth)
  3. {
  4.     if (root == NULL)
  5.         return 0;

  6.     if (depth == 0)
  7.         tree_print_node(root);
  8.     else {
  9.         return _tree_show_levelorder_recursive(root->left, depth - 1)
  10.                 + _tree_show_levelorder_recursive(root->right, depth - 1);
  11.     }
  12. }

  13. static void
  14. _tree_show_levelorder_nonrecursive(tree_t *root)
  15. {
  16.     if (root == NULL)
  17.         return;

  18.     seq_t *seq = seq_init();
  19.     seq_push(seq, root);
  20.     
  21.     while (!seq_empty(seq)) {
  22.         root = seq_pop(seq);
  23.         tree_print_node(root);
  24.         if (root->left)
  25.             seq_push(seq, root->left);
  26.         if (root->right)
  27.             seq_push(seq, root->right);
  28.     }
  29. }
 
11. 在一个字符串中找到第一个只出现一次的字符,如输入abaccdeff,则输出b

  1. static char
  2. first_single(char *str)
  3. {
  4.     int arr[255];
  5.     memset(arr, 0, sizeof(int) * 255);

  6.     char *p;
  7.     for (p = str; *p != '\0'; p++)
  8.         arr[*p]++;

  9.     for (p = str; *p != '\0'; p++) {
  10.         if (arr[*p] == 1)
  11.             return *p;
  12.     }

  13.     return '\0';
  14. }

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

  1. static int
  2. circle(int n, int m)
  3. {
  4.     int fn = 0, i;
  5.     for (i = 2; i <= n; i++)
  6.         fn = (fn + m) %i;
  7.     return fn;
  8. }
 
13. 给定两个正整数n和sum,打印出1到n之间整数和为sum的所有组合。如对于n = 6, sum = 10, 有10 = 2 + 3 + 5 = 1 + 2 + 3 + 4 ...

  1. static stack_t *s;

  2. static void
  3. find_sum(int sum, int n)
  4. {
  5.     if (n <= 0 || sum <= 0)
  6.         return;

  7.     stack_push(s, n);
  8.     
  9.     if (sum == n)
  10.         stack_show(s);

  11.     find_sum(sum - n, n - 1);
  12.     
  13.     stack_pop(s);
  14.     
  15.     find_sum(sum, n - 1);
  16. }
如果可以让整数重复的话,如10 = 3 + 3 + 4, 只需将上面的find_sum(sum - n, n - 1)改为find_sum(sum - n, n)即可
 
14. 输入一个字符串,打印出该字符串中所有字符的所有排列,如输入bac,则打印出abc, acb, bac, bca, cab, cba

  1. static void
  2. helper(char *str, char *begin)
  3. {
  4.     char    *p;
  5.     
  6.     if (str == NULL || begin == NULL)
  7.         return;
  8.         
  9.     if (*begin == '\0')
  10.         printf("%s\n", str);
  11.     else {
  12.         for (p = begin; *p != '\0'; p++) {
  13.             swap(p, begin);
  14.             helper(str, begin + 1);
  15.             swap(p, begin);
  16.         }
  17.     }
  18. }
15. 计算字符串的距离。我们定义了一套操作方法把两个不相同的字符串变为相同,如修改一个字符或增删一个字符,而需要操作的最小次数即为字符串的距离,给定任意两个字符串,写一个函数求其距离

  1. static int
  2. distance(char *strA, int aleft, int aright,
  3.             char *strB, int bleft, int bright)
  4. {
  5.     if (aleft > aright) {
  6.         if (bleft > bright)
  7.             return 0;
  8.         else
  9.             return bright - bleft + 1;
  10.     }
  11.     
  12.     if (bleft > bright) {
  13.         if (aleft > aright)
  14.             return 0;
  15.         else
  16.             return aright - aleft + 1;
  17.     }
  18.     
  19.     if (strA[aleft] == strB[bleft])
  20.         return distance(strA, aleft + 1, aright, strB, bleft + 1, bright);
  21.     else {
  22.         int t1 = distance(strA, aleft + 1,     aright, strB, bleft,         bright);
  23.         int t2 = distance(strA, aleft,         aright, strB, bleft + 1,     bright);
  24.         int t3 = distance(strA, aleft + 1,     aright, strB, bleft + 1,     bright);
  25.         return min(t1, t2, t3) + 1;
  26.     }
  27. }
 
16. 写一个轻量级的正则表达式的匹配引擎,如给定a*b?c和"aufbec",返回1,其中*表示0或多个字符,?表示1个字符

  1. static int
  2. match(char *pat, char *str)
  3. {
  4.     switch (*pat) {
  5.         case '\0' : return !*str;
  6.         case '*' :    return match(pat + 1, str) || *str && match(pat, str + 1);
  7.         case '?' : return *str && match(pat + 1, str + 1);
  8.         default     : return *pat == *str && match(pat + 1, str + 1);
  9.     }
  10. }















 
阅读(3709) | 评论(6) | 转发(1) |
给主人留下些什么吧!~~

GFree_Wind2012-04-24 15:57:54

jmy2446267: 那兄台可否给代码借我拜读一下,感激不尽啊.....
大概是2年前写的,现在已经很难找到了。
思路跟这个差不了多少,都是利用递归来完成的。

jmy24462672012-04-24 15:10:59

GFree_Wind: 轻量级的正则表达式的匹配引擎
——这个我以前也写过。后来不断地添加新的正则符号,常用的正则已经都满足了。.....
那兄台可否给代码借我拜读一下,感激不尽啊

GFree_Wind2012-04-24 12:28:15

轻量级的正则表达式的匹配引擎
——这个我以前也写过。后来不断地添加新的正则符号,常用的正则已经都满足了。

GFree_Wind2012-04-23 16:42:43

jmy2446267: 嗯,兄台可否说具体点.....
不好意思,应该是我理解错了。

jmy24462672012-04-23 14:03:57

GFree_Wind: 没有全部看完,感觉max_sum这个有问题吧。.....
嗯,兄台可否说具体点