java面试高频题1 --需要修改

java面试高频题1

浏览器输入一个地址回车之后都发生了什么?
URL 解析
DNS 查询
TCP 连接
处理请求
接受响应
渲染页面
参考答案1
URL 解析
DNS 查询
TCP 连接
发送HTTP请求
服务器处理请求
返回接受响应
关闭TCP
浏览器解析HTML
浏览器布局渲染页面
参考答案2
参考答案3

TCP 和 UTP 有什么区别
链路层:负责封装和解封装IP报文,发送和接受ARP/RARP报文等。
网络层:负责路由以及把分组报文发送给目标网络或主机。
传输层:负责对报文进行分组和重组,并以TCP或UDP协议格式封装报文。
应用层:负责向用户提供应用程序,比如HTTP、FTP、Telnet、DNS、SMTP等。

UDP:
面向无连接,具体来说就是:
在发送端,应用层将数据传递给传输层的 UDP 协议,UDP 只会给数据增加一个 UDP 头标识下是 UDP 协议,然后就传递给网络层了
在接收端,网络层将数据传递给传输层,UDP 只去除 IP 报文头就传递给应用层,不会任何拼接操作

有单播,多播,广播的功能,UDP是面向报文的,不可靠性,头部开销小,传输数据报文时是很高效的。

TCP:
TCP连接过程:三次握手, 四次挥手。
TCP协议的特点:
面向连接,仅支持单播传输, 面向字节流,可靠传输,提供拥塞控制(当网络出现拥塞的时候,TCP能够减小向网络注入数据的速率和数量,缓解拥塞),TCP提供全双工通信。
参考答案1
参考答案2

快速排序
该方法的基本思想是:
先从数列中取出一个数作为基准数。
分区过程,将比这个数大的数全放到它的右边,小于或等于它的数全放到它的左边。
再对左右区间重复第二步,直到各区间只有一个数。
参考答案1

//快速排序
void quick_sort(int s[], int l, int r)
{
     
    if (l < r)
    {
     
		//Swap(s[l], s[(l + r) / 2]); //将中间的这个数和第一个数交换 参见注1
        int i = l, j = r, x = s[l];
        while (i < j)
        {
     
            while(i < j && s[j] >= x) // 从右向左找第一个小于x的数
				j--;  
            if(i < j) 
				s[i++] = s[j];
			
            while(i < j && s[i] < x) // 从左向右找第一个大于等于x的数
				i++;  
            if(i < j) 
				s[j--] = s[i];
        }
        s[i] = x;
        quick_sort(s, l, i - 1); // 递归调用 
        quick_sort(s, i + 1, r);
    }
}

参考答案2
快速排序时间复杂度:O(nlogn)。
参考答案3

一条SQL执行的很慢的原因
一个 SQL 执行的很慢,我们要分两种情况讨论:
(1)大多数情况下很正常,偶尔很慢,则有如下原因
数据库在刷新脏页,例如 redo log 写满了需要同步到磁盘。
当我们要往数据库插入一条数据、或者要更新一条数据的时候,我们知道数据库会在内存中把对应字段的数据更新了,但是更新之后,这些更新的字段并不会马上同步持久化到磁盘中去,而是把这些更新的记录写入到 redo log 日记中去,等到空闲的时候,在通过 redo log 里的日记把最新的数据同步到磁盘中去。
不过,redo log 里的容量是有限的,如果数据库一直很忙,更新又很频繁,这个时候 redo log 很快就会被写满了,这个时候就没办法等到空闲的时候再把数据同步到磁盘的,只能暂停其他操作,全身心来把数据同步到磁盘中去的,而这个时候,就会导致我们平时正常的SQL语句突然执行的很慢,所以说,数据库在在同步数据到磁盘的时候,就有可能导致我们的SQL语句执行的很慢了。

执行的时候,遇到锁,如表锁、行锁。
这个就比较容易想到了,我们要执行的这条语句,刚好这条语句涉及到的表,别人在用,并且加锁了,我们拿不到锁,只能慢慢等待别人释放锁了。或者,表没有加锁,但要使用到的某个一行被加锁了,这个时候,我也没办法啊。
如果要判断是否真的在等待锁,我们可以用 show processlist这个命令来查看当前的状态哦,这里我要提醒一下,有些命令最好记录一下。

(2)这条 SQL 语句一直执行的很慢,则有如下原因。
没有用上索引:例如该字段没有索引;由于对字段进行运算、函数操作导致无法用索引。
如果我们在查询的时候,对字段进行了函数操作,也是会导致没有用上索引的 。

select * from t where pow(c,2) = 1000;

主键索引和非主键索引是有区别的,主键索引存放的值是整行字段的数据,而非主键索引上存放的值不是整行字段的数据,而且存放主键字段的值。

select * from t where 100 < c and c < 100000;

数据库选错了索引。
系统是有可能走全表扫描而不走索引的。
参考答案1
参考答案2

MySQL有哪些存储引擎以及他们之间的区别
存储引擎其实就是对于数据库文件的一种存取机制,如何实现存储数据,如何为存储的数据建立索引以及如何更新,查询数据等技术实现的方法。

InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。

MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比 较低,也可以使用。如果数据表主要用来插入和查询记录,则MyISAM引擎能提供较高的处理效率

MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存中的Memory引擎,MySQL中使用该引擎作为临时表,存放查询的中间结果

如果只有INSERT和SELECT操作,可以选择Archive,Archive支持高并发的插入操作,但是本身不是事务安全的。Archive非常适合存储归档数据,如记录日志信息可以使用Archiv。
参考答案1

InnoDB:支持事务处理,支持外键,支持崩溃修复能力和并发控制。如果需要对事务的完整性要求比较高(比如银行),要求实现并发控制(比如售票),那选择InnoDB有很大的优势。如果需要频繁的更新、删除操作的数据库,也可以选择InnoDB,因为支持事务的提交(commit)和回滚(rollback)。

MyISAM:插入数据快,空间和内存使用比较低。如果表主要是用于插入新记录和读出记录,那么选择MyISAM能实现处理高效率。如果应用的完整性、并发性要求比 较低,也可以使用。

MEMORY:所有的数据都在内存中,数据的处理速度快,但是安全性不高。如果需要很快的读写速度,对数据的安全性要求较低,可以选择MEMOEY。它对表的大小有要求,不能建立太大的表。所以,这类数据库只使用在相对较小的数据库表。

注意,同一个数据库也可以使用多种存储引擎的表。如果一个表要求比较高的事务处理,可以选择InnoDB。这个数据库中可以将查询要求比较高的表选择MyISAM存储。如果该数据库需要一个用于查询的临时表,可以选择MEMORY存储引擎。
参考答案2

两种存储引擎的大致区别表现在:1)InnoDB支持事务,MyISAM不支持,这一点是非常之重要。事务是一种高级的处理方式,如在一些列增删改中只要哪个出错还可以回滚还原,而MyISAM就不可以了。2)MyISAM适合查询以及插入为主的应用,InnoDB适合频繁修改以及涉及到安全性较高的应用3)InnoDB支持外键,MyISAM不支持4)从MySQL5.5.5以后,InnoDB是默认引擎5)InnoDB不支持FULLTEXT类型的索引6)InnoDB中不保存表的行数,如select count() from table时,InnoDB需要扫描一遍整个表来计算有多少行,但是MyISAM只要简单的读出保存好的行数即可。注意的是,当count()语句包含where条件时MyISAM也需要扫描整个表。7)对于自增长的字段,InnoDB中必须包含只有该字段的索引,但是在MyISAM表中可以和其他字段一起建立联合索引。8)清空整个表时,InnoDB是一行一行的删除,效率非常慢。MyISAM则会重建表。9)InnoDB支持行锁(某些情况下还是锁整表,如 update table set a=1 where user like '%lee%'有人说MYISAM只能用于小型应用,其实这只是一种偏见。如果数据量比较大,这是需要通过升级架构来解决,比如分表分库,读写分离,而不是单纯地依赖存储引擎。
参考答案3
参考答案4

如何查看SQL语句的执行状态
show processlist
参考答案1

qq用的是tcp还是udp
登陆采用TCP协议和HTTP协议,你和好友之间发送消息,主要采用UDP协议,内网传文件采用了P2P技术。
如果客户端使用UDP协议发出消息后,服务器收到该包,需要使用UDP协议发回一个应答包。如此来保证消息可以无遗漏传输。之所以会发生在客户端明明看到“消息发送失败”但对方又收到了这个消息的情况,就是因为客户端发出的消息服务器已经收到并转发成功,但客户端由于网络原因没有收到服务器的应答包引起的
如果是在内网里面的两个客户端传文件,QQ采用的是P2P技术,不需要服务器中转。
参考答案

jvm内存模型(Java内存模型以及JVM内存结构)
Java内存模型
一个本地变量可能是原始类型,在这种情况下,它总是“呆在”线程栈上。
一个本地变量也可能是指向一个对象的一个引用。在这种情况下,引用(这个本地变量)存放在线程栈上,但是对象本身存放在堆上。
一个对象可能包含方法,这些方法可能包含本地变量。这些本地变量仍然存放在线程栈上,即使这些方法所属的对象存放在堆上。
一个对象的成员变量可能随着这个对象自身存放在堆上。不管这个成员变量是原始类型还是引用类型。
静态成员变量跟随着类定义一起也存放在堆上。
存放在堆上的对象可以被所有持有对这个对象引用的线程访问。当一个线程可以访问一个对象时,它也可以访问这个对象的成员变量。如果两个线程同时调用同一个对象上的同一个方法,它们将会都访问这个对象的成员变量,但是每一个线程都拥有这个成员变量的私有拷贝。
添加链接描述

JVM内存结构
Java 虚拟机栈,本地方法栈,Java 堆,方法区,运行时常量池。
参考答案1

主要区域:堆(Heap),虚拟机栈(VM Stack),方法区(Method Area),本地方法栈(Native Method Stack),程序计数器(PC Register)。
参考答案2

编译参考答案
https://zhouj000.github.io/2019/07/09/java-base-jmm/
https://www.jianshu.com/p/bf158fbb2432

JVM内存结构中有栈堆等,栈这种数据结构
栈因为运行时的需要(如保存系统运行的上下文),需要进行址段的划分。由于栈只能向上增长,因此会限制住栈存储内容的能力。而堆不同,堆的大小可以根据需要动态增长。因此,堆与栈的分离,使得动态增长成为可能,相应栈中只需要记录堆中的一个地址即可。
参考答案1

从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。
参考答案2

[1]栈区(Stack):由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。我们在程序中定义的局部变量就是存放在栈里,当局部变量的生命周期结束的时候,它所占的内存会被自动释放。

[2]堆区(Heap):一般由程序员分配和释放,若程序员不释放,程序结束时可能由OS回收。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。我们在程序中使用c++中new或者c中的malloc申请的一块内存,就是在heap上申请的,在使用完毕后,是需要我们自己动手释放的,否则就会产生“内存泄露”的问题。
参考答案3

垃圾回收
*引用计数法:*这个方法实现简单,效率高,但是目前主流的虚拟机中并没有选择这个算法来管理内存,其最主要的原因是它很难解决对象之间相互循环引用的问题。

*可达性分析算法:*这个算法的基本思想就是通过一系列的称为 “GC Roots” 的对象作为起点,从这些节点开始向下搜索,节点所走过的路径称为引用链,当一个对象到 GC Roots 没有任何引用链相连的话,则证明此对象是不可用的。

无论是通过引用计数法判断对象引用数量,还是通过可达性分析法判断对象的引用链是否可达,判定对象的存活都与“引用”有关。
软引用可以加速JVM对垃圾内存的回收速度,可以维护系统的运行安全,防止内存溢出(OutOfMemory)等问题的产生。
参考答案1

aop和ioc
ioc:https://segmentfault.com/a/1190000019977321
https://www.jianshu.com/p/d96a2cf60636

time_wait状态
假设最终的ACK丢失,主机2将重发FIN,主机1必须维护TCP状态信息以便可以重发最终的ACK,否则会发送RST,结果主机2认为发生错误。TCP实现必须可靠地终止连接的两个方向(全双工关闭),主机1必须进入 TIME_WAIT 状态,因为主机1可能面 临重发最终ACK的情形。
参考答案1

四次挥手中,A 发 FIN, B 响应 ACK,B 再发 FIN,A 响应 ACK 实现连接的关闭。而如果 A 响应的 ACK 包丢失,B 会以为 A 没有收到自己的关闭请求,然后会重试向 A 再发 FIN 包。
如果没有 TIME_WAIT 状态,A 不再保存这个连接的信息,收到一个不存在的连接的包,A 会响应 RST 包,导致 B 端异常响应。

此时, TIME_WAIT 是为了保证全双工的 TCP 连接正常终止。
我们还知道,TCP 下的 IP 层协议是无法保证包传输的先后顺序的。如果双方挥手之后,一个网络四元组(src/dst ip/port)被回收,而此时网络中还有一个迟到的数据包没有被 B 接收,A 应用程序又立刻使用了同样的四元组再创建了一个新的连接后,这个迟到的数据包才到达 B,那么这个数据包就会让 B 以为是 A 刚发过来的。

此时, TIME_WAIT 的存在是为了保证网络中迷失的数据包正常过期。
参考答案2
擦考答案3

红黑树
每个节点要么是红色,要么是黑色;
根节点永远是黑色的;
所有的叶节点都是是黑色的(注意这里说叶子节点其实是上图中的 NIL 节点);
每个红色节点的两个子节点一定都是黑色;
从任一节点到其子树中每个叶子节点的路径都包含相同数量的黑色节点;

插入后调整红黑树结构
红黑树的第 5 条特征规定,任一节点到它子树的每个叶子节点的路径中都包含同样数量的黑节点。也就是说当我们往红黑树中插入一个黑色节点时,会违背这条特征。
同时第 4 条特征规定红色节点的左右孩子一定都是黑色节点,当我们给一个红色节点下插入一个红色节点时,会违背这条特征。
因此我们需要在插入黑色节点后进行结构调整,保证红黑树始终满足这 5 条特征。
情况1.父亲节点和叔叔节点都是红色。
情况2.父亲节点为红色,叔叔节点为黑色。

删除后的调整
https://zhuanlan.zhihu.com/p/25402654
https://blog.csdn.net/ChinaLeeSunnyBoy/article/details/79525456

B+树

B树相对于平衡二叉树的不同是,每个节点包含的关键字增多了,特别是在B树应用到数据库中的时候,数据库充分利用了磁盘块的原理(磁盘数据存储是采用块的形式存储的,每个块的大小为4K,每次IO进行数据读取时,同一个磁盘块的数据可以一次性读取出来)把节点大小限制和充分使用在磁盘快大小范围;把树的节点关键字增多后树的层级比原来的二叉树少了,减少数据查找的次数和复杂度;

特点:
1、B+树的层级更少:相较于B树B+每个非叶子节点存储的关键字数更多,树的层级更少所以查询数据更快;

2、B+树查询速度更稳定:B+所有关键字数据地址都存在叶子节点上,所以每次查找的次数都相同所以查询速度要比B树更稳定;

3、B+树天然具备排序功能:B+树所有的叶子节点数据构成了一个有序链表,在查询大小区间的数据时候更方便,数据紧密性很高,缓存的命中率也会比B树高。

4、B+树全节点遍历更快:B+树遍历整棵树只需要遍历所有的叶子节点即可,,而不需要像B树一样需要对每一层进行遍历,这有利于数据库做全表扫描。

B树相对于B+树的优点是,如果经常访问的数据离根节点很近,而B树的非叶子节点本身存有关键字其数据的地址,所以这种数据检索的时候会要比B+树快。

B+树的插入操作
1)若为空树,创建一个叶子结点,然后将记录插入其中,此时这个叶子结点也是根结点,插入操作结束。

2)针对叶子类型结点:根据key值找到叶子结点,向这个叶子结点插入记录。插入后,若当前结点key的个数小于等于m-1,则插入结束。否则将这个叶子结点分裂成左右两个叶子结点,左叶子结点包含前m/2个记录,右结点包含剩下的记录,将第m/2+1个记录的key进位到父结点中(父结点一定是索引类型结点),进位到父结点的key左孩子指针向左结点,右孩子指针向右结点。将当前结点的指针指向父结点,然后执行第3步。

3)针对索引类型结点:若当前结点key的个数小于等于m-1,则插入结束。否则,将这个索引类型结点分裂成两个索引结点,左索引结点包含前(m-1)/2个key,右结点包含m-(m-1)/2个key,将第m/2个key进位到父结点中,进位到父结点的key左孩子指向左结点, 进位到父结点的key右孩子指向右结点。将当前结点的指针指向父结点,然后重复第3步。
参考答案1

B+树的删除操作
1)删除叶子结点中对应的key。删除后若结点的key的个数大于等于Math.ceil(m-1)/2 – 1,删除操作结束,否则执行第2步。

2)若兄弟结点key有富余(大于Math.ceil(m-1)/2 – 1),向兄弟结点借一个记录,同时用借到的key替换父结(指当前结点和兄弟结点共同的父结点)点中的key,删除结束。否则执行第3步。

3)若兄弟结点中没有富余的key,则当前结点和兄弟结点合并成一个新的叶子结点,并删除父结点中的key(父结点中的这个key两边的孩子指针就变成了一个指针,正好指向这个新的叶子结点),将当前结点指向父结点(必为索引结点),执行第4步(第4步以后的操作和B树就完全一样了,主要是为了更新索引结点)。

4)若索引结点的key的个数大于等于Math.ceil(m-1)/2 – 1,则删除操作结束。否则执行第5步

5)若兄弟结点有富余,父结点key下移,兄弟结点key上移,删除结束。否则执行第6步

6)当前结点和兄弟结点及父结点下移key合并成一个新的结点。将当前结点指向父结点,重复第4步。

注意,通过B+树的删除操作后,索引结点中存在的key,不一定在叶子结点中存在对应的记录。
下面是一颗5阶B树的删除过程,5阶B数的结点最少2个key,最多4个key。

平衡树

为什么索引能加快查找效率
为什么能够提高查询速度?

索引就是通过事先排好序,从而在查找时可以应用二分查找等高效率的算法。
一般的顺序查找,复杂度为O(n),而二分查找复杂度为O(log2n)。当n很大时,二者的效率相差及其悬殊。

索引有什么副作用吗?
索引是有大量数据的时候才建立的,没有大量数据反而会浪费时间,因为索引是使用二叉树建立.
当一个系统查询比较频繁,而新建,修改等操作比较少时,可以创建索引,这样查询的速度会比以前快很多,同时也带来弊端,就是新建或修改等操作时,比没有索引或没有建立覆盖索引时的要慢。
索引并不是越多越好,太多索引会占用很多的索引表空间,甚至比存储一条记录更多。
参考答案1

跳跃表
跳跃表是一种随机化数据结构,查找、添加、删除操作都可以在对数期望时间下完成。
跳跃表目前在 Redis 的唯一作用,就是作为有序集类型的底层数据结构(之一,另一个构成有序集的结构是字典)。
为了满足自身的需求,Redis 基于 William Pugh 论文中描述的跳跃表进行了修改,包括:
score 值可重复。
对比一个元素需要同时检查它的 score 和 memeber 。
每个节点带有高度为 1 层的后退指针,用于从表尾方向向表头方向迭代。
参考答案1
https://juejin.im/post/57fa935b0e3dd90057c50fbc

redis
https://zhuanlan.zhihu.com/p/32540678
https://blog.csdn.net/ThinkWon/article/details/103522351

Linux的proc目录
proc是Linux系统下一个很重要的目录。 它跟/etc, /home等这些系统目录不同, 它不是一个真正的文件系统, 而是一个虚拟的文件系统。 它不存在于磁盘, 而是存在于系统内存中。 所以当你使用 ls -al /proc这条命令来查看proc目录时, 会看到其下面的所有文件的大小都为0字节。 proc以文件系统的方式为访问系统内核的操作提供接口。 很多系统的信息, 如内存使用情况, cpu使用情况, 进程信息等等这些信息,都可以通过查看/proc下的对应文件来获得。 proc文件系统是动态从系统内核读出所需信息的。
添加链接描述

怎么查看端口的状态?怎么查看某个进程的状态?
通过netstat命令进行简单查询
netstat命令各个参数说明如下:
  -t : 指明显示TCP端口
  -u : 指明显示UDP端口
  -l : 仅显示监听套接字(所谓套接字就是使应用程序能够读写与收发通讯协议(protocol)与资料的程序)
  -p : 显示进程标识符和程序名称,每一个套接字/端口都属于一个程序。
  -n : 不进行DNS轮询,显示IP(可以加速操作)
即可显示当前服务器上所有端口及进程服务,于grep结合可查看某个具体端口及服务情况··
netstat -ntlp //查看当前所有tcp端口·
netstat -ntulp |grep 80 //查看所有80端口使用情况·
netstat -ntulp | grep 3306 //查看所有3306端口使用情况·
参考答案1

Linux上进程有5种状态:

  1. 运行(正在运行或在运行队列中等待)
  2. 中断(休眠中, 受阻, 在等待某个条件的形成或接受到信号)
  3. 不可中断(收到信号不唤醒和不可运行, 进程必须等待直到有中断发生)
  4. 僵死(进程已终止, 但进程描述符存在, 直到父进程调用wait4()系统调用后释放)
  5. 停止(进程收到SIGSTOP, SIGSTP, SIGTIN, SIGTOU信号后停止运行运行)
    Linux中用ps命令查看进程状态。
    参考答案2

内存池实现

在编程中,为了避免由于频繁的malloc/free产生内存碎片,通常会在程序中实现自己的内存管理模块,即内存池。内存池的原理:程序启动时为内存池申请一块较大的内存,在程序中使用内存时,都由内存池进行分配,不再使用的内存交给内存池回收,用于再次分配。
参考答案1

内存池(Memery Pool)技术是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情况下)的内存块留作备用。当有新的内存需求时,就从内存池中分出一部分内存块,若内存块不够再继续申请新的内存。这样做的一个显著优点是尽量避免了内存碎片,使得内存分配效率得到提升。
不仅在用户态应用程序中被广泛使用,同时在Linux内核也被广泛使用,在内核中有不少地方内存分配不允许失败。作为一个在这些情况下确保分配的方式,内核开发者创建了一个已知为内存池(或者是 “mempool” )的抽象,内核中内存池真实地只是相当于后备缓存,它尽力一直保持一个空闲内存列表给紧急时使用,而在通常情况下有内存需求时还是从公共的内存中直接分配,这样的做法虽然有点霸占内存的嫌疑,但是可以从根本上保证关键应用在内存紧张时申请内存仍然能够成功。
参考答案2

进程间通信机制

Linux使用的进程间通信方式:
管道(pipe),流管道(s_pipe)和有名管道(FIFO)
信号(signal)
消息队列
共享内存
信号量
套接字(socket)
参考答案1
参考答案2

进程与线程的区别,共享的数据
https://www.nowcoder.com/questionTerminal/234895a70e0b40e19db7f3fbaabc5fa3

进程(Process) 是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。 在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。程序是指令、数据及其组织形式的描述,进程是程序的实体。
线程(thread) 是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

参考答案1
https://juejin.im/post/5dd53db7e51d453677066af4
https://juejin.im/post/5dd39e1be51d453fd16b196c

mysql主从同步怎么做

乐观锁与悲观锁的区别?

binlog日志

redis 持久化有哪几种方式,怎么选?

redis 主从同步是怎样的过程?

redis 的 zset 怎么实现的?

redis key 的过期策略

hashmap 是怎样实现的?为什么要用红黑树,而不用平衡二叉树?为什么在1.8中链表大于8时会转红黑树?HashMap为什么线程不安全的?

如何实现线程安全的hashmap?

select 和 epoll的区别

http与https的区别,加密怎么加的?

raft算法详细讲解

Kafka 选主怎么做的?

paxos和zookeeper的zab算法,他们之前有啥区别?

JavaHashMap的rehash有什么区别?

tcp怎么保证有序传输的?讲下tcp的快速重传和拥塞机制;

http与https有啥区别?说下https解决了什么问题,怎么解决的?说下https的握手过程。

算法:leetcode 53 最大子序和

算法:剪绳子(贪心或递归解决)

算法:给前序和中序遍历,重建二叉树

算法与数据结构 (手写代码实现)
1 大整数加、减、乘、除、求模运算实现

2 很多整数,找其中出现次数最多的那个数
https://www.cnblogs.com/eniac12/p/5296139.html

3 单链表翻转(两个指针如何实现)、查找、删除、插入以及双向链表、有序链表合并
Leetcode 23. Merge k Sorted Lists
Leetcode 206. Reverse Linked List
递归:

static Node reverseByRecursion(Node head){
     
    if(head == null || head.next == null){
     
        return head;
    }

    Node newHead = reverseByRecursion(head.next);

    head.next.next = head;
    head.next = null;
    return newHead;
}

非递归:

static class Node {
     
    int data;
    Node next;

    Node(int data){
     
        this.data = data;
    }
}

static Node reverseByLoop(Node head) {
     
    if (head == null || head.next == null){
     
        return head;
    }

    Node preNode = null;
    Node nextNode = null;
    while (head != null){
     
        nextNode = head.next;

        head.next = preNode;
        preNode = head;
        head = nextNode;
    }
    return preNode;
}

参考答案1

4 判断一个整数是否是2的整数次幂.(n&(n-1))

class Solution {
     
public:
    bool isPowerOfTwo(int i) {
     
        return ((i > 0) && ((i & (i - 1)) == 0));
        //2的n次幂肯定是大于0的   
    }
}

5 二分查找(注意边界条件)
https://blog.csdn.net/maoyuanming0806/article/details/78176957

6 常见排序算法的实现以及稳定性(快排跟归并考的很多)
https://blog.csdn.net/jianyuerensheng/article/details/51262984

7 字符串翻转(O(n))、匹配(KMP算法)
http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html
https://zhuanlan.zhihu.com/p/43824258

8 最长递增子序列(nlogn的算法)
[1,4, 2, 5]

public int findNumberOfLIS(int[] nums) {
     
        int n = nums.length, res = 0, max_len = 0;
        int[] len =  new int[n], cnt = new int[n];
        for(int i = 0; i<n; i++){
     
            len[i] = cnt[i] = 1;
            for(int j = 0; j <i ; j++){
     
                if(nums[i] > nums[j]){
     
                    if(len[i] == len[j] + 1)cnt[i] += cnt[j];
                    if(len[i] < len[j] + 1){
     
                        len[i] = len[j] + 1;
                        cnt[i] = cnt[j];
                    }
                }
            }
            if(max_len == len[i])res += cnt[i];
            if(max_len < len[i]){
     
                max_len = len[i];
                res = cnt[i];
            }
        }
        return res;
    }

9 链表判断是否有环,环的入口,两个链表是否相交(快慢指针)。

10 指定一个数组,求2个数的和等于指定的和(某一个数),如果是3,4,5,n个等于个的和(某一个数)呢?(可以看作背包问题)
https://zhuanlan.zhihu.com/p/30959069

11 跳台阶问题
https://blog.csdn.net/Hackbuteer1/article/details/6686747

public int numWays(int n) {
     
    if (n <= 1)
        return 1;
    int[] dp = new int[n + 1];
    dp[1] = 1;
    dp[2] = 2;
    for (int i = 3; i <= n; i++) {
     
        dp[i] = dp[i - 1] + dp[i - 2];
    }
    return dp[n];
}

你可能感兴趣的:(面试题,Java,复习)