四道微软面试算法题

http://topic.csdn.net/u/20081006/16/75461d49-6a8f-4684-84b6-aceee56c832f.html


(1)
一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。
请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻。
注意:
- 5个数值允许是乱序的。比如: 8 7 5 0 6
- 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4
- 0可以多次出现。
- 复杂度如果是O(n2)则不得分。

(2)
设计一个算法,找出二叉树上任意两个结点的最近共同父结点。
复杂度如果是O(n2)则不得分。

(3)
一棵排序二叉树,令 f=(最大值+最小值)/2,设计一个算法,找出距离f值最近、大于f值的结点。
复杂度如果是O(n2)则不得分。

(4)
一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。
复杂度最好是O(n),如果是O(n2)则不得分。



自己做了一下,程序如下
(1)
  1. // 返回0表示正确,否则返回失败的索引值
  2. int Check(int* p_data, int p_nCount)
  3. {
  4.     int i, end, zeroCount=0;
  5.     // 对数据进行从小到大排序
  6.     Sort(p_data, p_nCount);
  7.     // 检查0的个数
  8.     for(i=0; i<p_nCount; i++)
  9.     {
  10.         if(p_data[i]==0) zeroCount++;
  11.         else break;
  12.     }
  13.     
  14.     // 从5开始,到非0值的循环
  15.     i = p_nCount;
  16.     end = zeroCount+1;
  17.     while(i-- > end) 
  18.     {// 如果前后相差大于1,表示不连续
  19.         if((p_data[i] - p_data[i-1]) != 1)
  20.         {// 看能否用足够的0不上,计算剩余的0个数
  21.             zeroCount -= p_data[i] - p_data[i-1]-1;
  22.             if(zeroCount < 0) return i;
  23.         }
  24.     }
  25.     return 0;
  26. }


(2)
  1. void swap(Node** a, Node** b)
  2. {
  3.     Node * p = *a;
  4.     *b = *a;
  5.     *a = p;
  6. }
  7. void Check(Node * root, Node* a, Node* b)
  8. {
  9.     Node * parent = NULL;
  10.     if (a == NULL || b == NULL) printf("NULL/r/n");
  11.     printf("a=%d, b=%d, parent=", a->value, b->value);
  12.     if (a->GetLevel() < b->GetLevel()) // 检查两个节点深度,如果b比a深,交换a、b,让a的深度比b大
  13.     {
  14.         swap(&a, &b);
  15.     }
  16.     while(a->GetLevel() > b->GetLevel()) //对齐深度,这样才好比较
  17.     {
  18.         a = a->parent;
  19.     }
  20.     if (a == b) parent = a; //对齐后如果是同一节点,那么共同父节点取a
  21.     else
  22.     {
  23.         while(a->parent != b->parent) //检查a、b的父节点,如果不是,同时提升a、b节点
  24.         {
  25.             a = a->parent;
  26.             b = b->parent;
  27.         }
  28.         parent = a->parent;//最后得到共同父节点
  29.     }
  30.     printf("%d/r/n", parent->value);
  31. }

(3)
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <conio.h>
  4. #include "node.h"
  5. int sum = 0; // 比较次数总数
  6. Node * Check(Node * p, int f)
  7. {
  8.     sum++;
  9.     if (p==NULL) return NULL;
  10.     sum++;
  11.     if (p->value >= f)  // 当前节点大于f时,要检查左节点是否有更接近的值
  12.     {
  13.         Node* q = Check(p->left,f);
  14.         sum++;
  15.         return (q!=NULL)?q:p; // 左节点没合适的值时,用当前节点,否则要返回的节点
  16.     }
  17.     else // 当前节点小于f时,检查右节点是否有更接近的值
  18.     {
  19.         return Check(p->right,f);
  20.     }
  21. }

  22. // 给出根节点,计算最接近 f=(最大值+最小值)/2 的节点
  23. void Check(Node * root)
  24. {
  25.     Node * min = root->GetMinNode();
  26.     Node * max = root->GetMaxNode();
  27.     int f = (max->value + min->value)/2;
  28.     printf("min=%d, max=%d, f=%d , ", min->value, max->value, f);
  29.     sum=0;
  30.     Node* p = Check(root, f);
  31.     printf("target=%d/t/t%d/r/n", p->value,sum);
  32. }
  33. // 生成测试数据
  34. Node * CreateTestTree(void)
  35. {
  36.     int data[]={100,50,30,20,40,70,60,80,150,130,120,140,170,160,180};
  37.     int len = 15;
  38.     Node * root= new Node(data[0]);
  39.     for(int i = 1; i < len; i++)
  40.     {
  41.         root->Insert(data[i]);
  42.     }
  43.     return root;
  44. }
  45. // 主测试函数
  46. void main(void)
  47. {
  48.     clrscr();
  49.     Node * treeRoot = CreateTestTree();
  50.     treeRoot->PrintTree(40,1,3);
  51.     Node * p = NULL;
  52.     // 单独测试 Node * Check(Node * p, int f)
  53.     for (int i=10;i<=200 ;i+=5)
  54.     {
  55.         p = Check(treeRoot, i);
  56.         printf ("f=%d, node=%d/r/n",i,p->value);
  57.     }
  58.     // 测试题目3
  59.     Check(treeRoot);
  60.     delete treeRoot;
  61.     treeRoot = NULL;
  62.     return ;
  63. }


(4)
  1. #include <stdio.h>
  2. // 题目4:
  3. //一个整数数列,元素取值可能是1~N(N是一个较大的正整数)中的任意一个数,相同数值不会重复出现。设计一个算法,找出数列中符合条件的数对的个数,满足数对中两数的和等于N+1。
  4. //复杂度最好是O(n),如果是O(n2)则不得分。
  5. // buf中数据应该已经排序
  6. // 返回匹配数对数量
  7. // 算法中遍历1次数组,复杂度O(N)
  8. int c4(int* buf, int count)
  9. {
  10.     const int *p = buf; // 前指针
  11.     const int *q = buf+count-1; // 后指针
  12.     int n=*q+1; // N值
  13.     int c = 0; // 匹配数量
  14.     int compare = 0; //比较次数
  15.     
  16.     while (p<q) // 当前指针小于后指针时,循环数组
  17.     { compare++;
  18.         if ((*p + *q) == n) // 命中,计数加1,移动指针
  19.         { compare++; printf("%d,%d; ", *p,*q);
  20.             c++; p++; q--;
  21.         }
  22.         else
  23.         {
  24.             if ((*q + *p ) > n )
  25.                q--; // 当前2个值大于N时,前指针的值可能还有匹配,后指针左移
  26.             else
  27.                p++; // 当前2个值小于N时,后指针的值可能还有匹配,前指针右移
  28.         }
  29.     }
  30.     printf("compare=%d;/r/n ", compare); // 打印总比较次数
  31.     return c;
  32. }
  33. void test(int index, const int* buf, int count, int expected)
  34. {
  35.     for(int i=0; i<count; i++) printf("%2d,", buf[i]);
  36.     int actual = c4(buf, count);
  37.     printf("test %2d/t [%s] expected=%d, actual=%d/r/n/r/n",
  38.         index, expected==actual?"  ok ":"false", expected, actual);
  39. }
  40. int main(void)
  41. {
  42.     int i=1;
  43.     int t0[10]={1,2,3,4,5,95,96,97,98,99};
  44.     int t0_expected=5;
  45.     test(i++, t0, 10, t0_expected);
  46.     int t1[10]={1,2,13,14,15,95,96,97,98,99};
  47.     int t1_expected=2;
  48.     test(i++, t1, 10, t1_expected);
  49.     int t2[10]={1,2,3,44,55,95,96,97,98,99};
  50.     int t2_expected=3;
  51.     test(i++, t2, 10, t2_expected);
  52.     int t3[10]={1,12,13,87,88,95,96,97,98,99};
  53.     int t3_expected=3;
  54.     test(i++, t3, 10, t3_expected);
  55.     int t4[10]={1,20,30,40,50,51,96,97,98,99};
  56.     int t4_expected=1;
  57.     test(i++, t4, 10, t4_expected);
  58.     int t5[16]={1,12,13,14,20,30,31,32,33,70,80,95,96,97,98,99};
  59.     int t5_expected=3;
  60.     test(i++, t5, 16, t5_expected);
  61.     
  62.     
  63.     int t6[16]={1,3,4,12,13,14,20,30,31,70,80,85,86,87,88,99};
  64.     int t6_expected=6;
  65.     test(i++, t6, 16, t6_expected);
  66.     
  67.     return 0;
  68. }
用到的Node类
  1. // Node.h 
  2. #include <stdio.h>
  3. #ifndef NODE
  4. #define NODE
  5. class Node
  6. {
  7.     public :
  8.         int value;
  9.         Node* parent;
  10.         Node* left;
  11.         Node* right;
  12.     private:
  13.         int level;
  14.         // 打印树时的间隔比例因子
  15.         static const int SPACE;
  16.         int m_nMaxRow;
  17. public :
  18.     Node(void);
  19.     Node(int p_value);
  20.     Node(Node * p_parent);
  21.     Node(int p_value, Node * p_parent);
  22.     // 删除树
  23.     ~Node();
  24.     // 打印树
  25.     void PrintTree();
  26.     // 打印树 x = col, y = row,不是很好看 :P
  27.     void PrintTree(int x, int y, int z);
  28.     // 获取树深度
  29.     int GetLevel();
  30.     // 找最小值节点
  31.     Node* GetMinNode();
  32.     // 找最大值节点
  33.     Node* GetMaxNode();
  34.     // 插入新数据
  35.     Node* Insert(int p_value);
  36. };
  37. #endif
  1. // Node.cpp
  2. #include <stdio.h>
  3. #include <conio.h>
  4. #include "node.h"
  5. //using namespace std;
  6. const int Node::SPACE = 3;
  7. Node::Node(void)
  8. {
  9.     m_nMaxRow = 0;
  10.     parent = NULL;
  11.     left = NULL;
  12.     right = NULL;
  13.     level = -1;
  14. }
  15. Node::Node(int p_value)
  16. {
  17.     m_nMaxRow = 0;
  18.     value = p_value;
  19.     parent = NULL;
  20.     left = NULL;
  21.     right = NULL;
  22.     level = -1;
  23. }
  24. Node::Node(Node * p_parent)
  25. {
  26.     m_nMaxRow = 0;
  27.     parent = p_parent;
  28.     left = NULL;
  29.     right = NULL;
  30.     if(p_parent) level = p_parent->level+1;
  31. }
  32. Node::Node(int p_value, Node * p_parent)
  33. {
  34.     m_nMaxRow = 0;
  35.     value = p_value;
  36.     parent = p_parent;
  37.     left = NULL;
  38.     right = NULL;
  39.     if(p_parent) level = p_parent->level+1;
  40. }
  41. // 删除树
  42. Node::~Node()
  43. {
  44.     if (this->left) {delete left; left = NULL;}
  45.     if (this->right) {delete right; right = NULL;}
  46. }
  47. // 打印树
  48. void Node::PrintTree()
  49. {
  50.     if (this->left) this->left->PrintTree();
  51.     printf("%d ",this->value);
  52.     if (this->right) this->right->PrintTree();
  53. }
  54. // 打印树
  55. // x = col, y = row
  56. void Node::PrintTree(int x, int y, int z)
  57. {
  58.     if (x<0) x = 0;
  59.     if (y>25) return;
  60. //      if (y>m_nMaxRow) m_nMaxRow = y;
  61.     if (this->left) this->left->PrintTree(x-SPACE-z-z, y+1, z-1);
  62.     gotoxy(x, y);
  63.     printf("%d ",this->value);
  64.     if (this->right) this->right->PrintTree(x+SPACE+z+z, y+1, z-1);
  65. }
  66. // 获取树深度
  67. int Node::GetLevel()
  68. {
  69.     // 如果已经初始化,直接返回
  70.     if (level != -1)
  71.         return level;
  72.     // 否则算计深度
  73.     level = 0;
  74.     Node * p = this->parent;
  75.     while(p != NULL)
  76.     {
  77.         level ++;
  78.         p = p->parent;
  79.     }
  80.     return level;
  81. }
  82. // 找最小值节点
  83. Node* Node::GetMinNode()
  84. {
  85.     if (this->left != NULL) return this->left;
  86.     else return this;
  87. }
  88. // 找最大值节点
  89. Node* Node::GetMaxNode()
  90. {
  91.     if (this->right != NULL) return this->right;
  92.     else return this;
  93. }
  94. // 插入新数据
  95. Node* Node::Insert(int p_value)
  96. {
  97.     if (p_value > this->value)
  98.     {
  99.         if(this->right) return this->right->Insert(p_value);
  100.         else return this->right = new Node(p_value, this);
  101.     }
  102.     else
  103.     {
  104.         if(this->left) return this->left->Insert(p_value);
  105.         else return this->left = new Node(p_value, this);
  106.     }
  107. }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值