您的位置:首页 > 其它

笔试算法题(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);

解题:

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐