笔试算法题(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个整数.但这个数组已被旋转过多次,次数不详.找出数组中的某个元素. * 能够假定数组元素原先是按从小到大的顺序排列的. */ /** * 思路:数组 ...
随机推荐
- 【411】COMP9024 Assignment1 问题汇总
1. 构建 Makefile 文件后运行错误,undefined reference to 'sqrt' 实际上是没有链接math数学库,所以要 $gcc test.c –lm //-lm就是链接到m ...
- 一步一步学Vue(六)
本篇继续介绍vue-router,我们需要要完成这样个demo:<分页显示文章列表>:这里我们以博客园首页列表为例简化处理: 按照上图框选所示,简单分为蓝色部分文章组件(ArticleIt ...
- bzoj P2045 方格取数加强版【最大费用最大流】
今天脑子不太清醒,把数据范围看小了一直TTTTLE-- 最大费用最大流,每个格子拆成两个(x,y),(x,y)',(x,y)向(x,y)'连一条费用a[x][y]流量1的边表示选的一次,再连一条费用0 ...
- bzoj 1610: [Usaco2008 Feb]Line连线游戏【瞎搞】
阴沟翻船.jpg 居然忘了除0的情况 枚举两两之间的线,把斜率装起来排个序去个重就好了 真是水的一晚上呢 #include<iostream> #include<cstdio> ...
- bzoj 1912: [Apio2010]patrol 巡逻【不是dp是枚举+堆】
我是智障系列.用了及其麻烦的方法= =其实树形sp就能解决 设直径长度+1为len(环长) 首先k=1,直接连直径两端就好,答案是2*n-len 然后对于k=2,正常人的做法是树形dp:先求直径,然后 ...
- 【转】Spring,Spring MVC及Spring Boot区别
对于一个Java开发者来说,Spring可谓如雷贯耳,无论是Spring框架,还是Spring引领的IOC,AOP风格,都对后续Java开发产生的深远的影响,同时,Spring社区总能及时响应开发者的 ...
- Create the first sql server 2016 mobile report;创建 第一个 sqlserver 2016 Mobile report
在微软收购了datazen之后,sqlserver2016 集成了mobilereport,mobile report 基于html5,兼容各类主流浏览器,之前ssrs2008 R2中很多chart类 ...
- 关于tomcat一些简介
window下,在tomcat的bin目录下,用cmd输入startup.bat 即可启动tomcat 成功启动Tomcat后,通过访问http://localhost:8080/便可以使用Tomca ...
- JS-表格数据的添加与删除、搜索
<!doctype html><html><head><meta charset="utf-8"><title>JS练习 ...
- Java-超市购物小票案例-详细介绍
1.1 超市购物购物小票需求分析 用户循环进行三个操作: 1.输入购买数量,代表为所购买货物的数量赋值,从而计算每项商品金额 2.打印小票,将已有数据打印 3.退出系统(因为该程序为循环操作,无法终 ...