链表
当删除一个节点时,并不一定要删除这个节点本身,可以把下一个节点的内容复制出来覆盖被删除节点的内容,然后把下一个节点删除。(提高单链表的删除效率,不用从头遍历链表,但删除的是最后一个节点时,仍需要从头遍历到前一个节点)
当我们用一个指针遍历链表不能解决问题时,可以尝试用两个指针遍历链表,让其中一个指针遍历的快一些。
如:(1)链表倒数第k个节点
思路:两个指针间隔k-1,第二个指针到达末尾,第一个位置即为结果。
(2)链表中间节点(三等分点)
思路:一个指针一次一步,另一个指针一个两步(三步),走的快的指针到达末尾时,走的慢的指针即为结果。
(3)判断单链表是否形成环形结构
思路:一个指针一次一步,另一个指针一次两步,快指针追上慢指针,就是环形,若快指针到达末尾都没有追上,就不是环形。
(4)找到环的入口点?
答:假设slow,fast第一次交点为z,slow走过的距离:a+b,fast走过的距离:a+b+c+b,因为fast速度是slow的2倍,有a+2b+c=2(a+b),则a=c,此时两个指针分别从x和z开始走,每次都走一步,再次相遇即为入口点。(即:一个指针先走环大小个节点,然后两个指针一起走)
复杂链表的复制,复杂链表中每个节点除了有一个next指针指向下一个节点外,还有一个sibling指向链表中的任意节点?
答:o(n)不用辅助空间。根据原始链表中的每个节点N创建对应的节点N’,将N’链接在N的后面,若原始链表中N的sibling指向节点S,则N’的sibling指向S’,偶数位置的节点链接起来就是复制出来的链表。
如何求树中两个节点的最低公共祖先?
答:1.二叉搜索树
从根节点出发遍历树,如果当前节点都大于输入的两个节点,下一步遍历当前节点的左子树,如果当前节点小于输入的两个节点,下一步遍历右子树,直到遍历到当前节点比一个输入节点大比一个输入节点小。
2.任意树,有指向父节点的指针
从输入节点出发,沿着父节点指针一直到根节点,相当于求两个链表的第一个公共节点。
3.任意树,无指向父节点指针
从根节点开始遍历得到两条路径,求两条路径的第一个公共节点。
输入一棵二叉树的根节点,判断该树是不是二叉平衡树?(深度之差不超过1)
答:后序遍历二叉树,当遍历某节点的左右子树后,如果左右子树是平衡树,根据左右子树的深度判断它是不是平衡的,并得到当前节点的深度。(剑指offer)
构建乘积数组,给定一个数组A[0,1,……n-1],构建一个数组B[0,1,……n-1],其中B中元素B[i]=A[0]*A[1]*……*A[i-1]*A[i+1]*……*A[n-1],不能使用除法?变形:长度为n的整数数组,不允许除法,计算任意(n-1)个数的组合中乘积最大的一组?
答:
寻找数组中的最大值和最小值?
答:平常解法2*n,优化1.5n,先将前两个数中的最大值作为max,最小值作为min,而后每次从数组中取出相邻的两个数(不重复取),较大者更新max,较小者更新min.
不使用比较运算符求出两个数的最大值和最小值?
答:max=(a+b+|a-b|)/2 min=(a+b-|a-b|)/2,将a,b转化为long防止溢出。
找出数组中重复次数最多的数?
答:1.空间换时间 int count[i]记录i出现的次数,一般不这样做
2.Map<i,i出现次数>
数组中的一个数字减去它右边子数组中的一个数字可以得到一个差值,求所有可能差值中的最大值?
答:diff[i]表示前i+1个数中的差值最大值,max[i]前i+1个数的最大值,则:
Diff[i+1]=max{ diff[i],max[i]-a[i+1] }, max[i+1]=max{ max[i],a[i+1]},求解diff[i+1]与max[i+1]只用到了diff[i]与max[i],可以只用两个变量记录。
给定一个数组,数组中有重复元素,给出数组n1,n2,求这两个数字在数组中出现位置的最近距离?
答:遍历数组,当遇到n1时,记下n1出现的位置,求n1出现位置与上次遍历到n2出现位置之差,
遇到n2时,记下n2出现的位置,求n2出现位置与上次n1出现位置之差。
给定一个数字t,找出数字在数组中第一次出现的位置,数组中相邻元素之差为1?
答:与第一个元素(i=0)比较,如果相等就是结果,如果比第一个数大,则该数第一次出现位置必定在下标i+(t-a[i])或右边,如果小,第一次出现位置必定在下标i+(a[i]-t)或右边.
已知三个升序数组a[m]、b[n]、c[t],在三个数组中各找一个元素,使得组成的三元组距离最小?三元组距离:假设a[i]、b[j]、c[k]为三元组,距离=min(|a[i]-b[j]|,|a[i]-c[k]|,|b[j]-c[k]|)?
答:假设讨论到a[i],b[j],c[k],i,j,k之前的数的所有情况都谈论过,此时最小值的下标假设为i,无论j,k怎么移动求出的距离都大于a[i],b[j],c[k]之间的距离,所以i++,每次都移动最小值的下标,直到遍历完一个数组。
针对1、2、2、3、4、5这6个数字,打印出所有不同的排列,要求”4”不能在第3位,”3”与”5”不能相连?
答:将6个数字看成图的6个节点,两两之间有边,3与5不能相连,则3与5之间不存在边,深度遍历图,得到一个组合时判断”4”在不在第3位。
求平面上最多有多少个点共线?
答:枚举每一个点,计算该点与其它点的斜率,map<斜率,个数>个数加1。注意重合点和斜率无穷。
数组a[0,mid-1]和a[mid,n-1]是各自有序的(升序),对数组a[0,n-1]两个有序段进行合并,得到a[0,n-1]整体有序。空间复杂度o(1)?
答:遍历数组下标为0-mid-1的元素,如果a[i]<=a[mid],i++,否则a[i]与a[mid]交换,找到交换后的a[mid]在a[mid,n-1]中的正确位置(插入排序)。
给定一个长度为n的非空整数数组,找出使数组所有元素均相等的最少操作数,其中一次操作将其中n-1个数加上1?
答:将n-1个数加1,相当于n个数加1,一个数减1,所有数加1不会改变任何数的相对大小,无影响,问题变成每次选择一个数减1,要是次数最小,把所有数减到与最小值相等。(java程序员面试宝典)
给定一个非空整数数组,计算最少的操作次数使得整个数组的元素相等,一个操作的定义为选择一个元素+1或-1?
答:中位数。假设数组a[1……n],所有值转换的目标值为x=-max(在数轴最右边,即x<min(a[i])),操作次数为s=Σ(a[i]-x),x右移一位,则s=s=Σ(a[i]-x)-n,s减小n(x始终小于min(a[i])),当x位于[min(a[i]) , max(a[i])],x右移一位,x左边操作次数加1,右边操作次数减1,即s=s+L-R,随着x右移,L增加,R减小(L<R),即s不断减小,直到L=R.目标值就是中位数。
最大公约数?
答:1.辗转相除法 2.辗转相减法 x,y的公约数也是x-y与y的公约数,x-y与y的公约数也是x与y的公约数,因此x-y
与y的公约数相等
3.辗转相除法除法性能低,减法次数太多,将1和2结合起来
若x,y都是偶数,f(x,y)=2*f(x>>1,y>>1)
若x偶数,y奇数,f(x,y)=f(x>>1,y)
若x奇数,y偶数,f(x,y)=f(x,y>>1)
若x,y都奇数,f(x,y)=f(y,x-y)
在一个长度为n的数组中所有数字都在0到n-1范围内,数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。找出数组中任意一个重复的数字?
答:空间复杂度o(1).如果数组中没有重复的数字,那么当数组排序之后数字i将出现在下标为i的位置。从头到尾扫描数组中的每个数字,当扫描到下标为i的数字时,比较这个数字m是否等于i,如果等于扫描下一个数字,如果不等于,将m与下标为m的数字比较,如果相等,说明重复,不相等则继续将下标为m的数字放到正确位置,重复这个过程。
二叉排序树
给定一颗二叉排序树,寻找第k小元素?(k大时,左右子树相反)
答:方法一:
计算左子树元素个数left,如果left+1=k,根节点就是第k小元素,left>=k,在左子树找第k小元素,left+1<k,在右子树找第k-left-1小元素。
方法二:在中序遍历的过程中进行比较。
判断一个数组是不是二叉搜索树的后序遍历结果?(前序)
答:后序遍历最后一个为根节点,前面数字分成两部分:一部分左子树(小于根节点),一部分右子树(大于根节点)。从头开始找到左子树的边界,如果右子树不全大于根节点,不是结果。否则递归判断左右子树。(从栈中取数据打印)
求二叉树中节点的最大距离?
答:左子树距根节点的最大距离+右子树距根节点的最大距离 (程序员面试笔试宝典)
按之字形顺序打印二叉树?
答:两个栈。当打印某一层节点时,把下一层子节点保存到相应栈中。当前打印的是奇数层时,先保存左子节点再保存右子节点到第一个栈中,是偶数层时,先保存右子节点再保存左子节点第二个栈中。
实时排名
海量用户网站,用户拥有积分,积分随时更新,每次用户登录时显示其当前积分排名?
答:方法1:数组(n)
数组rank[s]表示积分s所对应的排名,查询积分s对应的排名时,直接返回rank[s],当用户积分从s更新为s+n时,只影响积分在s到s+n-1的用户,只需要把rank[s]到rank[s+n-1]的数组元素加1即可。
方法2:线段树(log)
是一种二叉搜索树,对于树中每一个非叶子节点[a,b],左儿子表示区间[a,(a+b)/2],右儿子表示区间[(a+b)/2+1,b],因此是平衡二叉树。
积分区间组成的线段树,最终得到1000000个区间[0,1)、[1,2)……[999999,1000000)。
实现热搜词提示
答:字典树+topk
跳跃表
倒排索引
定位单词出现在哪些文章中.(搜索引擎)
持久化数据结构
将一个数据结构的历史状态全都保存下来,能够快速查找之前出现过的某个状态。
1.持久化单链表
2.持久化二叉树
内省排序(IntroSort)
思想:由快速排序开始,当递归深度达到一定程度时,转换为堆排序。最坏时间复杂度仍保持O(nlogn)。
K sum问题
给定n个数字,在其里面找到所有满足条件的k个数字,使k个数字之和等于target(不能重复)?
2sum情况:对数字先排序,设定头尾指针,当指针移动时,表示该指针所指向的数字在2个数字里面的所有情况都已经讨论完毕,这样两指针只能向中间移动,当两指针所指元素和等于target时,左指针加1,右指针减1,当小于target时,左指针加1,大于target时,右指针减1,直到左右重合。
3sum情况:先排序,枚举确定第三个数字,然后对剩下数字进行 2sum。
例如:排序后a b c d e,第一次枚举a,剩下b c d e进行2sum,第二次枚举b,只需对c d e进行2sum(b可以满足a的所有情况都已经得到,相当于a可以满足b所有情况都已经得到)。
精确表达浮点数(分数),有限小数或无限循环小数转化为分数?
答:
输入一个正数s,找到所有和为s的连续正数序列(至少包含两个数)?
答:两个数small,big分别表示序列最小值和最大值。初始化small=1,big=2,如果small到big的序列和大于s,small++(包含small的都已经找到),如果小于s,big++,直到small到(1+s)/2为止。相等,small++,big++.
滑动窗口最大值,给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值?
答:剑指offer
时间复杂度
算法中基本操作重复执行的次数(一般最深层循环内的语句)是问题规模n的某个函数,时间度量记为T(n)=O(f(n)),简称时间复杂度。
定理:若A(n)=amnm+am-1nm-1+……+a1n+a0是一个m次多项式,则A(n)=O(nm)
二叉树
先序遍历(递归):
void PreorderTraverse(BTNode *T){
If(T!=NULL){
Visit(T->data);
PreorderTraverse(T->Lchild);
PreorderTraverse(T->Rchild);
}
}
中序遍历(递归):
void InorderTraverse(BTNode *T){
If(T!=NULL){
InorderTraverse(T->Lchild);
Visit(T->data);
InorderTraverse(T->Rchild);
}
}
后序遍历:(递归)
void PostorderTraverse(BTNode *T){
If(T!=NULL){
PostorderTraverse(T->Lchild);
PostorderTraverse(T->Rchild);
Visit(T->data);
}
}
二叉树应用1:
折痕向下,叫做下折痕,否则叫做上折痕,纸条从下向上对折,对折n次,从上向下计算所有折痕方向?
答:二叉树中序遍历。
平衡二叉树
性质:(1)左右子树深度之差的绝对值不大于1
(2)左右子树也都是平衡二叉树
B_树
B+树
哈希函数
冲突处理:
1.开放地址法
当冲突发生时,形成某个探测序列,按此序列逐个探测散列表的其他地址,直到找到给定的关键字或一个空地址位置。计算公式:
Hi=(H(key)+di)%m
M->散列表长度 di->第i次探测的增量
1.1线性探测法
排序算法总结
1.直接插入排序
将待排序的记录Ri,插入到已排好序的记录R1,R2,……Ri-1中。刚开始排序时,R[1]时排好序的。
2.折半插入排序
3.直接选择排序
通过n-i次关键字间的比较,从n-i+1个记录中选取关键字最小的记录,然后和第i个记录进行交换。
4.冒泡排序
依次比较相邻的两个记录的关键字,若两个记录是反序的,则进行交换,直到没有反序的记录为止。
5.希尔排序(缩小增量法)
(1)先取一个正整数d1(<n)作为第一个增量,将所有相隔d1的记录进行直接插入排序。
(2)取新的增量d2<d1,重复(1);直至增量di=1为止。
6.快速排序(在数据基本有序的情况下不适用)
7.归并排序 应用场景:外部排序
public static void merge_sort(int a[],int begin,int end){
if(begin>=end)
return;
int[] tem=new int[a.length];
int mid=(begin+end)/2;
int index=begin;
merge_sort(a,begin,mid);
merge_sort(a,mid+1,end);
int beginLeft=begin;
int endLeft=mid+1;
while(beginLeft<=mid&&endLeft<=end){
if(a[beginLeft]<=a[endLeft]){
tem[index++]=a[beginLeft++];
}else{
tem[index++]=a[endLeft++];
}
}
while(beginLeft<=mid){
tem[index++]=a[beginLeft++];
}
while(endLeft<=end){
tem[index++]=a[endLeft++];
}
for(int i=begin;i<=end;i++){
a[i]=tem[i];
}
}
8.堆排序
void adjustHeap(int * arrs, int p, int len){
int curParent = arrs[p];
int child = 2* p + 1;
while(child < len){
if(child+1<len&&arrs[child]<arrs[child+1]){
child++; //较大孩子的下标
}
if(curParent<arrs[child]){
arrs[p]=arrs[child];
p=child;
child=2*p+1;
}
else
break;
}
arrs[p]=curParent;
}
void heapSort(int * arrs, int len){
for(int i = arrLen /2 -1; i>=0; i--)
adjustHeap(arrs, i, arrLen);
for(int i = arrLen -1; i>=0; i--){
int maxEle = arrs[0];
arrs[0] = arrs[i];
arrs[i] = maxEle;
adjustHeap(arrs, 0, i);
}
}
当元素基本有序(连续递增递减子序列的个数)的情况下,快排可以转化为归并排序。
当待排序数组中元素个数较少时(47),插入排序优于快速排序(递归影响性能)。
四叉堆与二叉堆(操作一样):比二叉堆有更浅的深度和更好的CPU Cache命中率
海量数据随机抽取一个(数据总数不知道,只能遍历一次)?
答:第一次直接以第一个数据为result,第二次以1/2的概率将第二个数据作为result,第三次以1/3的概率将第三个数据作为result,第n次以1/n的概率将第n个数据作为result。
证明:当讨论第i个数,选择第i个数的概率为1/i,后面i+1……n不被选择的概率为i/(i+1),……(n-1)/n,第i个数作为result的概率为(1/i)*(i/i+1)*……(n-1/n)=1/n
程序:
海量数据随机抽取k个?
答:前k个数作为初始值,第i(i=k+1,……n)个数以k/i的概率随机替换已经选择的k个元素。
数学归纳:
1.当i=k+1时,第k+1个元素被选择的概率为k/(k+1),前k个元素的概率为不被替换的概率:1-1/k*k/(k+1)=k/(k+1)
2.假设当j=i的时候,以k/i的概率选择第i个元素,前j个元素被选择的概率为k/i
3.那么当j=i+1时,第j个元素被选择的概率为k/i+1,前j-1个元素被选择的概率为:k/i*(1-1/k* k/i+1)=k/i+1
判断一个数m是不是2的n次方?
答:如果是2的n次方,二进制中只能有一个1,只需要判断m&(m-1)==0.
把一个数组的奇数放到偶数前面?
答:从前向后找到一个偶数,再从后向前找到一个奇数,然后交换。
同样的,将数组中负数移到非负数前面等,为了可扩展性,将奇偶判断逻辑变成一个函数指针。
求n!二进制表示中最低位1的位置?
答:奇数相乘最低位为1,乘以2相当于向左移动一位,相当于求n!中质因数2的个数。
求数组异或值最大的两个数?
答:字典树。以所有数的二进制建一颗深度33的树(从高位开始),从根到叶子节点的路径代表一个数,对数组中的每一个元素取反到字典树中搜索最大的异或值,查找字典树时,如果当前节点不为空(异或为1)继续沿着这个分支走下去,如果为空,转向另一个分支。
求平方根、三次开方?
答:牛顿迭代法、二分法。
判断两个矩形相交以及相交区域?
答:
判断两个矩形中心坐标的水平和垂直距离。
第一个矩形左上角、右下角坐标分别为(xa1,ya1)、(xa2,ya2)
第二个矩形左上角、右下角坐标分别为(xb1,yb1)、(xb2,yb2)
只要满足如下两个式子,就说明相交:
水平距离:|(xa1+xa2)/2 - (xb1+xb2)/2|<= (xa2-xa1)/2 +(xb2-xb1)/2
垂直距离:|(ya1+ya2)/2 - (yb1+yb2)/2|<= (ya2-ya1)/2+(yb2-yb1)/2
假设相交矩形左上角、右下角坐标为(xc1,yc1)、(xc2,yc2),则:
Xc1=max(xa1,xb1)
Yc1=min(ya1,yb1)
Xc2=min(xa2,xb2)
Yc2=max(ya2,yb2),如果求出的xc1<=xc2&&yc1<=yc2,也可说明相交。
判断任意四个点是否组成矩形、正方形?
答:枚举可能的对角线,对角线相等且中点重合即为矩形,如果邻边等长即为正方形。
判断点是否在三角形内?
答:若在内部,沿着三角形边界逆时针走,该点一定在边界的左边,根据向量叉积的正负判断。
把无序数组排成波动数组?a1<a2>a3<a4>……
答:把数组从小到大排序,此时数组全部为<关系,从第二个元素开始,每次选两个相邻元素交换位置,每个元素不能重复选。
判断一个数是否在40亿个数当中?
答:1.位图法。申请512M内存,每一bit代表对应数是否存在。负数可以2bitmap
2.将所有数按照二进制最高位为0和1分成两半,每次在其中一半,按照次高位再次减半。
判断字符串是否在一个集合中(海量字符串集合)?如:检查英语单词是否拼写正确
答:bloom filter(布隆过滤器)。Bit数组+k个哈希函数。每加入一个字符串,经过k个哈希函数将对应bit置1,判断时,如果k个位置不全为1,字符串一定不在集合中,如果全为1,字符串可能在集合中(冲突造成)。 空间时间效率高,但牺牲了正确率。
几亿个数据排序?
答:1.位图法。2.归并,例如分成1000个有序文件,在内存中建一个1000个元素的堆,取走堆顶后,每次从堆顶对应的文件中再取一个元素。
在2.5亿个整数中找出不重复的整数?
答:2-BitMap.每个数分配2bit,00->不存在,01->出现一次,10->出现多次
求n个集合的交集?
答:1.当集合中的元素很分散
对于第一个集合中的每个元素依次判断是否同时存在其他集合。
2.不分散
位图法。求n个位图的与。
一个进栈序列1,2,……n,有多少个出栈序列?
答:假设k最后出栈,那么前面k-1个已经出栈,出栈序列个数为f(k-1),后面n-k个数有f(n-k)个出栈序列,所以总共有f(n)=f(0)*f(n-1)+f(1)*f(n-2)+……f(k-1)*f(n-k)+……f(n-1)*f(0)
三个人玩牌,地主20张,其他两个人17张,大小王在一个人手里的概率?
答:大(小)王在地主手里的概率是在其他人手里概率的20/17倍,因此在一个人手里的概率为(20*20+17*17+17*17)/(54*54)
洗牌算法保证是随机的?实现随机播放音乐
答:第一张牌就是第一个位置,第二张牌随机放在1,和2的任一个位置,第三张牌随机放在1,2,3的任一个位置,第n张牌随机放在1,2,……n的任一个位置。
有1-10亿数字的乱序数组,其中少了一个数,怎么快速找到丢失的数字?
答:1.把这组数依次异或,然后在跟1-10亿依次异或,得到的数就是丢失的数。2.和相减
二进制字符串”abcdabeaa”,需要能够根据编码,解码回原来的字符串,最少需要多长的二进制字符串?
答:出现次数:a:4 b:2 c:1 d:1 e:1,生成哈夫曼编码:a:1 b:01 c:001 d:0000 e:0001
合并两个有序数组A1,A2,A1末尾有足够多的空余空间容纳A2,把A2所有数字插入到A1中并别保证有序?
答:从尾到头比较A1和A2的数字,把较大的数字复制到A1合适位置。
一个整型数组除了两个数字之外,其他的数字都出现了两次,找出这两个只出现一次的数字。时间复杂度O(n),空间复杂度O(1)?
答:如果一个数组里除了一个数字之外,其他数字都出现了两次,那么所有数字异或的结果就是所求。可以把原数组分成两个子数组,每个子数组只包含一个只出现一次的数字,其他数组都出现两次。由于存在两个只出现一次的数字,整个数组最终异或的结果不为0,找到结果的二进制中第一个为1的位置,假设为N,按照第N位分别为1和0将数组分成两个子数组。
一个整型数组除了3个数字之外,其他的数字都出现了两次,找出这3个只出现一次的数字?
答:同上题。3个数字的二进制必有1位,数字a在此位为1,b、c在此位为0,以此将数组分成两组,一组求出a,另一组求出b,c.
一个整型数组,所有数字都出现n次,只有一个出现一次,找出这个数?
答:出现n次的数字中,每个数字的二进制位中对应位的1都是n个,最后每个二进制位是1的个数都是n的倍数,如果不为n的倍数,说明要找的数对应二进制位为1.
存在函数A()可以产生0~9的随机数,且等概率的产生每个随机数,现在需要编写一个函数B(),使得产生数字1、2、3的概率为0.2,数字4的概率为0.4。
答:public int B( ){
Switch(A()){
Case 0,6,7,8,9: B( );
Case 1,2,3: Print(1 or 2 or 3);break;
Case 4,5:Print(4);break;
}
}
无序数组a[n],求大小相邻的实数的差的最大值,要求时间和空间复杂度为线性?
答:桶排序思想。假设数组中最大值为max,最小值为min,把区间[min,max]划分为n+1个区间,每个区间宽度为(max-min)/(n+1),n个数放入n+1个桶,至少有一个空桶,min位于第一个桶,max位于最后一个桶,所有空桶位于中间部分,则差最大值为空桶后一个桶的最小值减去空桶前一个桶的最大值。
A[i]是一个严格递增的整数数组,其中所有数都不相等,求出其中所有A[i]=i的数字,分析时间复杂度?
答:令B[i]=A[i]-i;则B[i+1]-B[i]=A[i+1]-A[i]-1>=0;说明B[i]是单增的,相当于二分查找B[i]=0,时间复杂度为logn.不需要求出B.
()字符串中只可能由A、B、C三个字母组成,如果任何相邻的三个字母相同,就非法,求长度为n的合法字符串有多少?
答:动态规划。
dp[i][0]:长度为i、最后两位不同的合法串个数
dp[i][1]:长度为i、最后两位相同的合法串个数
递推:dp[i][0]=dp[i-1][0]*2+dp[i-1][1]*2;
dp[i][1]=dp[i-1][0]
找出第k大元素?
答:1.快排partition
优先队列(小顶堆) 包含k个元素的小顶堆,如果元素比堆顶大就替换堆顶。
找出排序数组中从小到大的第k个数,从左到右,从上到下递增?
答:小顶堆。最小元素先进堆,而后出堆,将比这个出堆的元素大的进堆,只进右边和下边元素(这样可以保证所有元素的影响都考虑过,如果只进最小的,没进那个元素的影响就会被忽略,进过的不能重复进),出堆k次。
找出数组中出现次数超过一半的元素?
答: 思路1(o(n)):相当于找第n大元素--->快排partition(o(n)),但会改变原数组的顺序
思路2(o(n)):不断从数组中去掉任意两个不同的元素,最后剩余的就是结果。
实现:变量cur存储目标值,num存储对应个数,每次取出一个数和cur比较,如果相等,num++,如果不等,如果num=0,
cur存储当前值,num=1,如果num!=0,num--。
求数据流中的中位数?如果是奇数,中位数为排序后中间的数字,否则为中间两个数的平均值?
答:最大堆+最小堆。最大堆中所有数据小于最小堆中所有数据,且两堆的数据个数之差不能超过1。当两堆个数之和为偶数时,新数据需要插入最大堆,但是如果新数据大于最小堆堆顶,先将新数据插入最小堆,再将最小堆堆顶插入最大堆(最小堆堆顶删除),奇数类似。
在一个文件中有 10G个整数,乱序排列,要求找出中位数。内存限制为 2G?
答:桶排序。根据最高的8bit,划分为256个桶,根据每个数的最高8bit,将其放入对应桶,把每个桶中的数据写入磁盘文件并记录桶内数据量,计算中位数在第几个桶,如果该桶数据量小于2G,全部读入内存找,否则根据次高8bit将该桶数据再次划分到256个桶。
现在有一个0-30000的随机数生成器,根据这个随机数生成器,设计一个抽奖范围是0-350000的彩票中奖列表,其中包含20000个中奖号码?
答:桶排序。将0-350000划分为35/3=12个区间,每个区间长度<30000,根据随机数生成器生成随机数,再加上该区间的基数。每个区间产生随机数个数20000/12.
求一个数的临近稍大数且是2的幂次方?O(1)
答:不断复制左边的1到相邻右边,保证从最高位的1开始以后全是1。
给定a、b两个文件,各存放50亿个url,找出a、b共同的url?
答:遍历a、b,对每个url,hash(url)%1000分别放到1000个小文件中。相同的url只会在a、b对应的小文件中。
二叉树a,b,判断b是否是a的子结构?
答:二叉树序列化+kmp
序列化a,b为两个字符串,判断b是否是a的子串。序列化可以根据先序遍历,遇到NULL用一个特殊字符代替,根据此字符串可以构建唯一一个二叉树。
实现一个函数,判断一颗二叉树是不是对称的?如果一颗二叉树和它的镜像一样,那么它是对称的.
答:前序遍历的对称遍历:先遍历父节点,再遍历右子节点,最后遍历左子节点。通过比较二叉树的前序遍历序列和对称前序遍历判断是不是对称的。(剑指offer)
求函数最宽上升下降区间?
答:遍历数组,找到所有的峰底(比左右都小),相邻峰底之差最大的即为所求。
在8*8的国际象棋上摆放8个皇后,任意两个不在同一行,不在同一列或同一对角线,求符合条件的摆法个数?
答:数组column[8],column[i]表示第i行的列号,对column全排列,只需判断每一个排列中的皇后不在同一对角线,即任意i,j,i-j=column[i]-column[j]或j-i=column[j]-column[i]不存在。
把数组排成最小的数?
答:定义一种排序规则:任意两个数字m,n,如果mn<nm(字符串比较),m应该在n前面,否则n在m前面,按此规则对所有数排序,依次拼接起来就是最小数。(证明剑指offer)
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变?
答:如:I am a student.到student. a am I.先翻转句子中的所有字符,再翻转每个单词中的字符。
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部,如abcdefg左旋转2位的结果为cdefgab。
答:以分割位置将字符串划分为左右两部分,先分别翻转左右两部分,再翻转整个字符串。
给定两个字符串s1,s2,要求判定s2是否能被s1循环移位得到的字符串包含?如s1=AABCD,s2=CDAA,返回true
答:判断s2是否在s1s1上。
给定一个字符串s和一个目标字符串t,在字符串s中找到包括t所有字母的最小子串?
答:头尾指针。初始,头尾指针都指向s开头,先尾指针向后移动直到包含t中所有字母为止(包括出现次数),头指针再向后移动直到其中一个字母出现个数不够为止,比较此时首尾指针之间的是否为最小子串。然后首指针向后移动一位,继续下次循环(还是从移动尾指针开始)。
有一根27厘米的细木杆,在3厘米、7厘米、11厘米、17厘米、23厘米这五个位置上各有一只蚂蚁,木杆很细,不能同时通过两只蚂蚁,开始时,蚂蚁的头朝左朝右是任意的,它们只会朝前走或掉头,但不会回退。当任意两只蚂蚁碰头时,它们会同时掉头朝反方向走。假设蚂蚁每秒走一厘米的距离,求所有蚂蚁离开木杆的最短时间和最长时间?
答:蚂蚁相遇后朝反方向走,可以看做蚂蚁相遇后擦肩而过,这样蚂蚁的运动是独立的。分别计算每个蚂蚁离开木杆的时间,最长时间-离自己较远的一端,最短时间-离自己较近的一端。
某公司在中国和美国各有一台服务器,服务器中各自装有存储相关信息的大文件,这两份文件内容是一致的。某日,由于故障导致美国服务器中的文件中的某几个字节出错了,现在希望找出是哪几个字节出错。请给出算法,要求时间复杂度越低越好?
答:rsync。http://coolshell.cn/articles/7425.html
最小覆盖圆:给出平面上的一些点,要求用一个最小的圆,把所有的点包围起来?
答:假设前i-1个点的最小覆盖圆已经找到,加入第i个点,如果第i个点在圆内或圆上,讨论下一个点,否则,新的覆盖圆必定经过第i个点,这时,寻找包含第i个点和前j(j从0到i-1,如果j在第i个点和前j-1个点的圆内,则跳过)个点的最小圆,因为这时的最小圆直径必定大于等于第i个点和第j个点的距离,首先以此距离作为直径,依次讨论前k(0<k<j)个点是否在此圆内,如果不在,新的覆盖圆为点i、点j、点k形成三角形的外接圆。
1到n的整数中,判断1出现的次数?
答:分别判断1出现在个位、十位、百位、千位……
假设n为abc,
1出现在个位c:当c>1时,前缀从0到ab,个数为ab+1
当c==1时,前缀从0到ab,个数为ab+1
当c==0,前缀从0到ab-1,个数为ab
1出现在十位b:当b>1,前缀从0到a,后缀从0到9,个数为10a
当b==1,前缀从0到a-1,后缀从0到9,个数10a
前缀为a,后缀从0到c,个数c+1
当b==0,前缀从0到a-1,后缀从0到9,个数10a
1出现在百位a:当a>1,后缀个数10*10=100
当a==1,后缀从0到bc,个数bc+1
大量int型数据的压缩存储方式:java中int占4字节,可以在一个字节中最高位表示int数据是否表示完成,剩下7位表示有效数据,这样一个int压缩存储占1-5字节。
统计论坛在线人数分布,假设有一个论坛,其注册ID有2亿个,每个ID从登陆到退出都会向日志文件记录登陆时间和退出时间,统计一天中论坛在线用户分布,粒度为秒?
答:一天3600*24=86400秒,数组a[i]对应第i秒的人数变化,每个用户的登陆时间对应的整数加1,退出时间减1,数组b[k]对应第k秒的在线人数,b[k]=b[k-1]+a[k]
腾讯服务器每秒有2w个QQ同时在线,找出5min内重新登陆的QQ号并打印出来?
答:桶排序。2w*300=600w个桶,每个桶存储指定范围的QQ结构体,假设QQ一共10^10个,每个桶个数10^10/(600w)个,插入时按QQ号从小到大排序,同时记录最后登录时间,使用大小为300的循环链表,每个链表记录同一秒的QQ号地址,方便删除过时的QQ。