• 笔试算法题(24):找出出现次数超过一半的元素 & 二叉树最近公共父节点


    出题:数组中有一个数字出现的次数超过了数组长度的一半,请找出这个数字;

    分析:

    • 解法1:首先对数组进行排序,时间复杂度为O(NlogN),由于有一个数字出现次数超过了数组的一半,所以如果二分数组的话,划分元素肯定就是这个数字;
    • 解法2:首先创建1/2数组大小的Hash Table(哈希表可以替代排序时间,由于一个数字出现超过了数组的一半,所以不同元素个数肯定不大于数组的一半),空间复杂度O(N),顺序扫描映射数 组元素到Hash Table中并计数,最后顺序扫描Hash Table,计数超过数组大小一半的元素就是这个数字,时间复杂度O(N);
    • 解法3:由于一个数字的出现次数超过了数组的一半,所以这个数字的次数减去其他数字的总和的值仍旧大于0;定义两个变量,一个存储数字A,一个进行计数 C;当下一个数字与A相同,则C+1,当下一个数字与A不同,则C-1;当C等于0的时候,A初始化为下一个数字。最终A就是这个数字,时间复杂度 O(N);
    • 扩展问题:如果有三个数字出现的次数均超过了数字总数的1/4,则如何快速找到这三个数字。同样使用解法3的思想,同时删除4个不同的数字,直到找不到4个不同的数字,剩下的数字就是由三个不同数字重复出现组成的。时间复杂度O(N);

    解题:

     1 int HalfElementArray(int *array, int length) {
     2         int num=array[0];
     3         int count=1;
     4 
     5         for(int i=1;i<length;i++) {
     6                 if(array[i]==num)
     7                         count++;
     8                 else {
     9                         if(count==0)
    10                                 num=array[i+1];
    11                         else
    12                                 count--;
    13                 }
    14         }
    15         return num;
    16 }
    17 void QuarterElementsArray(int *array, int length) {
    18         int num1=array[0],num2=array[1],num3=array[2];
    19         int count1=0,count2=0,count3=0;
    20 
    21         for(int i=3;i<length;i++) {
    22                 if(array[i]==num1)
    23                         count1++;
    24                 else if(array[i]==num2)
    25                         count2++;
    26                 else if(array[i]==num3)
    27                         coun3++;
    28                 else {
    29                         if(count1==0)
    30                                 num1=array[i+1];
    31                         else if(count2==0)
    32                                 num2=array[i+1];
    33                         else if(count3==0)
    34                                 num3=array[i+1];
    35                         else {
    36                                 num1--;num2--;num3--;
    37                         }
    38                 }
    39                 printf("%D, %d, %d
    ",num1,num2,num3);
    40         }
    41 }

    出题:给定一棵二叉树,以及两个节点,要求找到两个节点最近的公共父节点;

    分析:

    • 解法1:遍历整棵树分别查找两个节点,并分别使用两个Stack(Queue)结构保存根节点到查找节点的路径,然后查找路径中的第一个公共节点(最后一个公共节点),时间复杂度为O(N),空间复杂度为O(logN);
    • 解法2:使用递归方法,从当前节点的左右子树中确定是否包含两个节点A和B,如果A和B都在左子树中则递归,如果A和B都在右子树中则递归,如果一个在左 子树一个在右子树则当前节点就是第一个公共节点,由于每次都需要判断子树是否包含某个节点,所以时间复杂度为O(N^2),没有额外的空间复杂度;

    解题:

      1 struct Node {
      2         int value;
      3         Node *left;
      4         Node *right;
      5 };
      6 
      7 /**
      8  * 使用stack结构保存root到target节点的路径的解法
      9  * 算法复杂度为O(N),空间复杂度为O(NlogN)
     10  * */
     11 
     12 /**
     13  * stack实现
     14  * */
     15 class MyStack {
     16 private:
     17         Node **array;
     18         int capability;
     19         int top;
     20 public:
     21         MyStack(int cap=5): array((Node**)malloc(sizeof(Node)*cap)), capability(cap), top(0) {}
     22         ~MyStack() {delete [] array;}
     23 
     24         bool isFull() {
     25                 return top == capability;
     26         }
     27         bool isEmpty() {
     28                 return top == 0;
     29         }
     30         int freeSlot() {
     31                 return capability - top;
     32         }
     33 
     34         /**
     35          * top当前的位置就是下一个push元素所在的slot
     36          * */
     37         bool push(Node *n) {
     38                 if(isFull()) return false;
     39                 array[top++]=n;
     40                 return true;
     41         }
     42         bool pop(Node **n) {
     43                 if(isEmpty()) return false;
     44                 *n=array[--top];
     45                 return true;
     46         }
     47         void ShowStack() {
     48                 int temp=top-1;
     49                 printf("
    ");
     50                 for(int i=0;i<=temp;i++)
     51                         printf("%d, ",array[i]->value);
     52                 printf("
    ");
     53         }
     54 };
     55 
     56 Node* GetLowerFather(MyStack *sfirst, MyStack *ssecond) {
     57 
     58 }
     59 
     60 bool FindTargetPath(Node *root, Node *target, MyStack *mstack) {
     61         if(root==NULL)
     62                 return false;
     63         mstack->push(root);
     64 
     65         if(root==target)
     66                 return true;
     67         else if(FindTargetPath(root->left,target, mstack))
     68                 return true;
     69         else if(FindTargetPath(root->right,target, mstack))
     70                 return true;
     71         else {
     72                 mstack->pop(NULL);
     73                 return false;
     74         }
     75 }
     76 
     77 Node* FindCommonFather1(Node *root, Node *first, Node *second) {
     78         if(first==NULL || second==NULL)
     79                 return NULL;
     80         MyStack *sfirst=new MyStack(10);
     81         MyStack *ssecond=new MyStack(10);
     82 
     83         if(FindTargetPath(root, first, sfirst) &&
     84                         FindTargetPath(root, second, ssecond))
     85                 return GetLowerFather(sfirst, ssecond);
     86         else {
     87                 printf("
    bad input");
     88                 return NULL;
     89         }
     90 }
     91 
     92 /**
     93  * 直接使用递归的解法
     94  * 算法复杂度为O(N^2)
     95  * */
     96 
     97 bool HasNode(Node *root, Node *target) {
     98         if(root==NULL) return false;
     99         if(root==target) return true;
    100         /**
    101          * 仅当左子树没有找到target的时候,才处理右子树
    102          * */
    103         bool bleft=HasNode(root->left,target);
    104         if(!bleft) {
    105                 return HasNode(root->right,target);
    106         } else {
    107                 return true;
    108         }
    109 }
    110 
    111 Node* FindCommonFather(Node *cur, Node *first, Node *second) {
    112         /**
    113          * 如果当前节点为NULL,返回NULL
    114          * */
    115         if(cur == NULL) return NULL;
    116         /**
    117          * 判断是否first和second都在左子树
    118          * 注意处理first和second为同一个节点的情况
    119          * 注意处理first和second中一个节点是另一个节点的父节点的情况
    120          * */
    121         bool bfirstleft=false, bsecondleft=false;
    122         if(cur->left != NULL) {
    123                 bfirstleft=HasNode(cur->left,first);
    124                 bsecondleft=HasNode(cur->left,second);
    125                 if(bfirstleft && bsecondleft) {
    126                         /**
    127                          * 这里的||操作可以处理当一个节点是另一个节点的
    128                          * 父节点的情况
    129                          * */
    130                         if(cur->left==first || cur->left==second)
    131                                 return cur;
    132                         else
    133                                 return FindCommonFather(cur->left,first,second);
    134                 }
    135         }
    136         /**
    137          * 判断是否first和second都在右子树
    138          * 注意处理first和second为同一个节点的情况
    139          * 注意处理first和second中一个节点是另一个节点的父节点的情况
    140          * */
    141         bool bfirstright=false, bsecondright=false;
    142         if(cur->right != NULL) {
    143                 bfirstright=HasNode(cur->right,first);
    144                 bsecondright=HasNode(cur->right,second);
    145                 if(bfirstright && bsecondright) {
    146                         /**
    147                          * 这里的||操作可以处理当一个节点是另一个节点的
    148                          * 父节点的情况
    149                          * */
    150                         if(cur->right==first || cur->right==second)
    151                                 return cur;
    152                         else
    153                                 return FindCommonFather(cur->right,first,second);
    154                 }
    155         }
    156         /**
    157          * 判断是否first在左且second在右,或者first在右且
    158          * second在左
    159          * */
    160         if((bfirstleft && bsecondright) ||
    161                         (bfirstright && bsecondleft))
    162                 return cur;
    163         return NULL;
    164 }
  • 相关阅读:
    2017级面向对象程序设计 作业三
    2017级面向对象程序设计 作业二
    2017级面向对象程序设计 作业一
    寒假作业之总结
    寒假第三次作业
    寒假第二次作业 与电梯有关的代码问题
    我印象中最深刻的三位老师
    Alpha冲刺Day5
    Alpha冲刺Day4
    Alpha冲刺Day3
  • 原文地址:https://www.cnblogs.com/leo-chen-2014/p/3745075.html
Copyright © 2020-2023  润新知