笔试算法题(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个整数.但这个数组已被旋转过多次,次数不详.找出数组中的某个元素. * 能够假定数组元素原先是按从小到大的顺序排列的. */ /** * 思路:数组 ...
随机推荐
- UVa 11440 Help Tomisu (数论欧拉函数)
题意:给一个 n,m,统计 2 和 n!之间有多少个整数x,使得x的所有素因子都大于M. 析:首先我们能知道的是 所有素数因子都大于 m 造价于 和m!互质,然后能得到 gcd(k mod m!, m ...
- 真正认识 realloc 的工作方式(转载)
转自:http://www.cnblogs.com/ren54/archive/2008/11/20/1337545.html realloc 用过很多次了.无非就是将已经存在的一块内存扩大. cha ...
- bzoj 3732: Network【克鲁斯卡尔+树链剖分】
先做最小生成树,这样就保证了最大值最小 然后随便用个什么东西维护一下最大值,我用的树剖log^2,倍增会更快 #include<iostream> #include<cstdio&g ...
- 洛谷P4550 收集邮票(概率期望)
传送门 神仙题啊……这思路到底是怎么来的…… ps:本题是第$k$次买邮票需要$k$元,而不是买的邮票标号为$k$时花费$k$元 我们设$g[i]$表示现在有$i$张,要买到$n$张的期望张数,设$P ...
- Uix Kit 快速建站前端开发套件-工具箱
这个产品维护已经有一年了(由于业务需求不同,目前没有做中文版,产品本身是针对国外网站),自己本身是做UI出生,开发只是业余爱好,仅仅作为平时工作的需要.杂七杂八会一些前后端开发.并非职业码农! 我是一 ...
- Ubuntu18安装sublime 3
转自 https://blog.csdn.net/qq_41590417/article/details/80461075 wget -qO - https://download.sublimetex ...
- [Usaco2017 Feb]Why Did the Cow Cross the Road II (Gold)
Description 上下有两个长度为n.位置对应的序列A.B, 其中数的范围均为1~n.若abs(A[i]-B[j])<= 4,则A[i]与B[j]间可以连一条边. 现要求在边与边不相交的情 ...
- Java Annontation(注解)详解
java中经常用到注解(Annontation),索性整理了下关于注解的相关知识点: 一.概念 Annontation是Java5开始引入的新特征,类似与.NET 中的attribute.中文名称一般 ...
- 467 Unique Substrings in Wraparound String 封装字符串中的独特子字符串
详见:https://leetcode.com/problems/unique-substrings-in-wraparound-string/description/ C++: class Solu ...
- Windows 7操作系统下PHP 7的安装与配置(图文详解)
前提博客 Windows 7操作系统下Apache的安装与配置(图文详解) 从官网下载 PHP的官网 http://www.php.net/ 特意,新建这么一个目录 ...