笔试算法题(24):找出出现次数超过一半的元素 & 二叉树最近公共父节点
2014-05-22 10:12
375 查看
出题:数组中有一个数字出现的次数超过了数组长度的一半,请找出这个数字;
分析:
解法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:遍历整棵树分别查找两个节点,并分别使用两个Stack(Queue)结构保存根节点到查找节点的路径,然后查找路径中的第一个公共节点(最后一个公共节点),时间复杂度为O(N),空间复杂度为O(logN);
解法2:使用递归方法,从当前节点的左右子树中确定是否包含两个节点A和B,如果A和B都在左子树中则递归,如果A和B都在右子树中则递归,如果一个在左 子树一个在右子树则当前节点就是第一个公共节点,由于每次都需要判断子树是否包含某个节点,所以时间复杂度为O(N^2),没有额外的空间复杂度;
解题:
分析:
解法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);
解题:
int HalfElementArray(int *array, int length) { int num=array[0]; int count=1; for(int i=1;i<length;i++) { if(array[i]==num) count++; else { if(count==0) num=array[i+1]; else count--; } } return num; } void QuarterElementsArray(int *array, int length) { int num1=array[0],num2=array[1],num3=array[2]; int count1=0,count2=0,count3=0; for(int i=3;i<length;i++) { if(array[i]==num1) count1++; else if(array[i]==num2) count2++; else if(array[i]==num3) coun3++; else { if(count1==0) num1=array[i+1]; else if(count2==0) num2=array[i+1]; else if(count3==0) num3=array[i+1]; else { num1--;num2--;num3--; } } printf("%D, %d, %d\n",num1,num2,num3); } }
出题:给定一棵二叉树,以及两个节点,要求找到两个节点最近的公共父节点;
分析:
解法1:遍历整棵树分别查找两个节点,并分别使用两个Stack(Queue)结构保存根节点到查找节点的路径,然后查找路径中的第一个公共节点(最后一个公共节点),时间复杂度为O(N),空间复杂度为O(logN);
解法2:使用递归方法,从当前节点的左右子树中确定是否包含两个节点A和B,如果A和B都在左子树中则递归,如果A和B都在右子树中则递归,如果一个在左 子树一个在右子树则当前节点就是第一个公共节点,由于每次都需要判断子树是否包含某个节点,所以时间复杂度为O(N^2),没有额外的空间复杂度;
解题:
struct Node { int value; Node *left; Node *right; }; /** * 使用stack结构保存root到target节点的路径的解法 * 算法复杂度为O(N),空间复杂度为O(NlogN) * */ /** * stack实现 * */ class MyStack { private: Node **array; int capability; int top; public: MyStack(int cap=5): array((Node**)malloc(sizeof(Node)*cap)), capability(cap), top(0) {} ~MyStack() {delete [] array;} bool isFull() { return top == capability; } bool isEmpty() { return top == 0; } int freeSlot() { return capability - top; } /** * top当前的位置就是下一个push元素所在的slot * */ bool push(Node *n) { if(isFull()) return false; array[top++]=n; return true; } bool pop(Node **n) { if(isEmpty()) return false; *n=array[--top]; return true; } void ShowStack() { int temp=top-1; printf("\n"); for(int i=0;i<=temp;i++) printf("%d, ",array[i]->value); printf("\n"); } }; Node* GetLowerFather(MyStack *sfirst, MyStack *ssecond) { } bool FindTargetPath(Node *root, Node *target, MyStack *mstack) { if(root==NULL) return false; mstack->push(root); if(root==target) return true; else if(FindTargetPath(root->left,target, mstack)) return true; else if(FindTargetPath(root->right,target, mstack)) return true; else { mstack->pop(NULL); return false; } } Node* FindCommonFather1(Node *root, Node *first, Node *second) { if(first==NULL || second==NULL) return NULL; MyStack *sfirst=new MyStack(10); MyStack *ssecond=new MyStack(10); if(FindTargetPath(root, first, sfirst) && FindTargetPath(root, second, ssecond)) return GetLowerFather(sfirst, ssecond); else { printf("\nbad input"); return NULL; } } /** * 直接使用递归的解法 * 算法复杂度为O(N^2) * */ bool HasNode(Node *root, Node *target) { if(root==NULL) return false; if(root==target) return true; /** * 仅当左子树没有找到target的时候,才处理右子树 * */ bool bleft=HasNode(root->left,target); if(!bleft) { return HasNode(root->right,target); } else { return true; } } Node* FindCommonFather(Node *cur, Node *first, Node *second) { /** * 如果当前节点为NULL,返回NULL * */ if(cur == NULL) return NULL; /** * 判断是否first和second都在左子树 * 注意处理first和second为同一个节点的情况 * 注意处理first和second中一个节点是另一个节点的父节点的情况 * */ bool bfirstleft=false, bsecondleft=false; if(cur->left != NULL) { bfirstleft=HasNode(cur->left,first); bsecondleft=HasNode(cur->left,second); if(bfirstleft && bsecondleft) { /** * 这里的||操作可以处理当一个节点是另一个节点的 * 父节点的情况 * */ if(cur->left==first || cur->left==second) return cur; else return FindCommonFather(cur->left,first,second); } } /** * 判断是否first和second都在右子树 * 注意处理first和second为同一个节点的情况 * 注意处理first和second中一个节点是另一个节点的父节点的情况 * */ bool bfirstright=false, bsecondright=false; if(cur->right != NULL) { bfirstright=HasNode(cur->right,first); bsecondright=HasNode(cur->right,second); if(bfirstright && bsecondright) { /** * 这里的||操作可以处理当一个节点是另一个节点的 * 父节点的情况 * */ if(cur->right==first || cur->right==second) return cur; else return FindCommonFather(cur->right,first,second); } } /** * 判断是否first在左且second在右,或者first在右且 * second在左 * */ if((bfirstleft && bsecondright) || (bfirstright && bsecondleft)) return cur; return NULL; }
相关文章推荐
- 二叉树的最近公共祖先、两个最远节点、第K层结点个数、出现次数超过一半的元素
- 在一个整型数组中有一个元素的出现次数超过了数组长度的一半,试设计一个 在时间上尽可能高效的算法,找出这个元素。
- 已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。
- 找出一个数组中出现次数超过一半的元素
- 已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
- Java实现 找出数组中出现次数超过数组长度一半的元素
- PHP实现找出数组中出现次数超过数组长度一半的数字算法示例
- 现在有一个整数数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
- 找出数组中出现次数超过一半的元素
- 现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数。
- 找出出现次数超过数组一半元素的数
- 一道算法题:找出数组中出现次数超过一半的数
- 找出数组中出现次数超过数组长度一半的元素
- 已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
- 找出数组中出现次数超过一半或者超过1/3的元素
- 现在有一个整数数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
- 现在有一个数组,已知一个数出现的次数超过了一半,请用O(n)的复杂度的算法找出这个数
- 找出整数数组中出现次数超过数组长度一半的元素(Java)
- 算法--找出数组中出现次数超过一半的数
- 找出出现次数超过一半的元素