笔试算法题(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);
解题:
int HalfElementArray(int *array, int length) {
int num=array[];
int count=;
for(int i=;i<length;i++) {
if(array[i]==num)
count++;
else {
if(count==)
num=array[i+];
else
count--;
}
}
return num;
}
void QuarterElementsArray(int *array, int length) {
int num1=array[],num2=array[],num3=array[];
int count1=,count2=,count3=;
for(int i=;i<length;i++) {
if(array[i]==num1)
count1++;
else if(array[i]==num2)
count2++;
else if(array[i]==num3)
coun3++;
else {
if(count1==)
num1=array[i+];
else if(count2==)
num2=array[i+];
else if(count3==)
num3=array[i+];
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=): array((Node**)malloc(sizeof(Node)*cap)), capability(cap), top() {}
~MyStack() {delete [] array;}
bool isFull() {
return top == capability;
}
bool isEmpty() {
return top == ;
}
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-;
printf("\n");
for(int i=;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();
MyStack *ssecond=new MyStack();
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;
}
笔试算法题(24):找出出现次数超过一半的元素 & 二叉树最近公共父节点的更多相关文章
- majority element(数组中找出出现次数最多的元素)
Given an array of size n, find the majority element. The majority element is the element that appear ...
- 算法题之找出数组里第K大的数
问题:找出一个数组里面前K个最大数. 解法一(直接解法): 对数组用快速排序,然后直接挑出第k大的数.这种方法的时间复杂度是O(Nlog(N)).N为原数组长度. 这个解法含有很多冗余,因为把整个数组 ...
- 前端算法题:找出数组中第k大的数字出现多少次
题目:给定一个一维数组,如[1,2,4,4,3,5],找出数组中第k大的数字出现多少次. 例如:第2大的数是4,出现2次,最后输出 4,2 function getNum(arr, k){ // 数组 ...
- 笔试算法题(19):判断两条单向链表的公共节点 & 字符集删除函数
出题:给定两个单向链表的头结点,判断其是否有公共节点并确定第一个公共节点的索引: 分析: 由于是单向链表,所以每个节点有且仅有一个后续节点,所以只可能是Y型交叉(每条链表中的某个节点同时指向一个公共节 ...
- 剑指Offer:找出数组中出现次数超过一半的元素
题目:找出数组中出现次数超过一半的元素 解法:每次删除数组中两个不同的元素,删除后,要查找的那个元素的个数仍然超过删除后的元素总数的一半 #include <stdio.h> int ha ...
- 从一亿个ip找出出现次数最多的IP(分治法)
/* 1,hash散列 2,找到每个块出现次数最多的(默认出现均匀)—–>可以用字典树 3,在每个块出现最多的数据中挑选出最大的为结果 */ 问题一: 怎么在海量数据中找出重复次数最多的一个 算 ...
- 笔试算法题(42):线段树(区间树,Interval Tree)
议题:线段树(Interval Tree) 分析: 线段树是一种二叉搜索树,将一个大区间划分成单元区间,每个单元区间对应一个叶子节点:内部节点对应部分区间,如对于一个内部节点[a, b]而言,其左子节 ...
- 一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵
题目描述: 一个N*M的矩阵,找出这个矩阵中所有元素的和不小于K的面积最小的子矩阵(矩阵中元素个数为矩阵面积) 输入: 每个案例第一行三个正整数N,M<=100,表示矩阵大小,和一个整数K 接下 ...
- 9.11排序与查找(三)——给定一个排序后的数组,包括n个整数,但这个数组已被旋转过多次,找出数组中的某个元素
/** * 功能:给定一个排序后的数组.包括n个整数.但这个数组已被旋转过多次,次数不详.找出数组中的某个元素. * 能够假定数组元素原先是按从小到大的顺序排列的. */ /** * 思路:数组 ...
随机推荐
- Wait示例分析
wait方法使"当前线程"进入阻塞(等待)状态. 示例分析: public class TestWait { public static void main(String[] ar ...
- 搭建CARDBOARD+ANDROID+unity3d的VR开发环境
一.下载最新unity3d(u3d官网) 二.下载最新cardboardsdkforunity(https://github.com/googlesamples/cardboard-unity) 三. ...
- 转载:Eclipse build Android时不生成apk问题解决方法
Eclisps有时build后不生成apk.没有对Eclise做过设置调整,android工程代码也是没有问题的.反正就是莫名奇妙的遇到两次,解决方法如下: 1. 设置:Preferences -&g ...
- UVA - 10859 Placing Lampposts 放置街灯
Placing Lampposts 传送门:https://vjudge.net/problem/UVA-10859 题目大意:给你一片森林,要求你在一些节点上放上灯,一个点放灯能照亮与之相连的所有的 ...
- ionic2 angular2 模板指令补充
向div中插入带有html标签的数据 [innerHTML]="item.content" 字符串截取指令 {{item.de ...
- 无法生成DH密钥对Could not generate DH keypair
Source from here Add this library to classpath(following is maven project) <dependency> < ...
- Permutation UVA - 11525(值域树状数组,树状数组区间第k大(离线),log方,log)(值域线段树第k大)
Permutation UVA - 11525 看康托展开 题目给出的式子(n=s[1]*(k-1)!+s[2]*(k-2)!+...+s[k]*0!)非常像逆康托展开(将n个数的所有排列按字典序排序 ...
- 修改SolrCloud在ZooKeeper中的配置文件操作记录
修改SolrCloud在ZooKeeper中的配置文件操作记录. 命令执行目录: /opt/solr-/server/scripts/cloud-scripts/ 1.下载配置文件 ./zkcli., ...
- for循环的阶乘
方法一: long sum=0; long num=1; for (long i = 1; i <=20; i++) { for(long j=i;j>0;j--){ num=num*j; ...
- POJ 2002 Squares 数学 + 必须hash
http://poj.org/problem?id=2002 只能说hash比二分快很多.随便一个hash函数都可以完爆二分. 判断是否存在正方形思路如下: 1.枚举任意两个点,作为正方形的一条边,那 ...