目录
一、MySQL主从同步是如何实现的
Binary log:主数据库的二进制日志。
Relay log:从服务器的中继日志。
第一步:master在每个事务更新数据完成之前,将该操作记录串行地写入到binlog文件中。
第二步:salve开启一个I/O Thread,该线程在master打开一个普通连接,主要工作是binlog dump process。如果读取的进度已经跟上了master,就进入睡眠状态并等待master产生新的事件。I/O线程最终的目的是将这些事件写入到中继日志中。
第三步:SQL Thread会读取中继日志,并顺序执行该日志中的SQL事件,从而与主数据库中的数据保持一致。
二、说一说HashMap的扩容机制
【得分点】
三个条件、翻倍扩容
【参考答案】
向HashMap中添加数据时,有三个条件会触发它的扩容行为:
1. 如果数组为空,则进行首次扩容。
2. 将元素接入链表后,如果链表长度达到8,并且数组长度小于64,则扩容。
3. 添加后,如果数组中元素超过阈值,即比例超出限制(默认为0.75),则扩容。
每次扩容时都是将容量翻倍,即创建一个2倍大的新数组,然后再将旧数组中的数组迁移到新数组里。由于HashMap中数组的容量为2^N,所以可以用位移运算计算新容量,效率很高。
三、什么是MVC
【得分点】
Model、View、Controller
【参考答案】
MVC是一种设计模式,在这种模式下软件被分为三层,即Model(模型)、View(视图)、Controller(控制器)。Model代表的是数据,View代表的是用户界面,Controller代表的是数据的处理逻辑,它是Model和View这两层的桥梁。将软件分层的好处是,可以将对象之间的耦合度降低,便于代码的维护。
Model:指从现实世界中抽象出来的对象模型,是应用逻辑的反应。它封装了数据和对数据的操作,是实际进行数据处理的地方。在MVC的三个部件中,模型拥有最多的处理任务。被模型返回的数据是中立的,模型与数据格式无关,这样一个模型能为多个视图提供数据,由于应用于模型的代码只需写一次就可以被多个视图重用,所以减少了代码的重复性。
View:是应用和用户之间的接口,它负责将应用显示给用户和显示模型的状态。MVC的好处之一在于它能为应用程序处理很多不同的视图。在视图中其实没有真正的处理发生,它只是作为一种输出数据并允许用户操纵的方式。
Controller:控制器负责视图和模型之间的交互,控制对用户输入的响应、响应方式和流程。它主要负责两方面的动作,一是把用户的请求分发到相应的模型,二是把模型的改变及时地反映到视图上。
四、算法题:实现两个数组相乘
三重循环
public int[][] solve (int[][] a, int[][] b) {
// write code here
int n = a.length;
int[][] ans = new int[n][n];
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
for(int k = 0; k < n; k++) {
ans[i][j] += a[i][k] * b[k][j];
}
}
}
return ans;
}
五、DNS(域名系统)是什么?
得分点:
应用层协议、域名服务器DNS、采用分布式查询、机器名通过DNS系统采用递归查询或迭代查询可得到对应的IP地址
参考答案
:
域名系统DNS是在Internet因特网使用的系统,主要用来把机器的名字(后来被称为域名)转换为IP地址,它是应用层协议,为了提高查询效率,每个域名服务器中都有高速缓存,存放着查询过的表单。域名服务器分为根域名服务器、顶级域名服务器、权限域名服务器和本地域名服务器。DNS查询的过程简单描述就是:主机向本地域名服务器发起某个域名的DNS查询请求,如果本地域名服务器查询到对应IP,就返回结果,否则本地域名服务器直接向根域名服务器发起DNS查询请求,要么返回结果,要么告诉本地域名服务器下一次的请求服务器IP地址,下一次的请求服务器可能是顶级域名服务器也可能还是根域名服务器,然后继续查询。循环这样的步骤直到查询到结果,本地域名服务器拿到结果返回给主机。
六、算法题:给定一个长度为n的数组arr,返回arr的最长无重复元素子数组的长度,无重复指的是所有数字都不相同。
子数组是连续的,比如[1,3,5,7,9]的子数组有[1,3],[3,5,7]等等,但是[1,3,7]不是子数组
解法一:我们使用两个指针,一个i一个j,最开始的时候i和j指向第一个元素,然后i往后移,把扫描过的元素都放到map中,如果i扫描过的元素没有重复的就一直往后移,顺便记录一下最大值max,如果i扫描过的元素有重复的,就改变j的位置
public int maxLength(int[] arr) {
if (arr.length == 0)
return 0;
HashMap<Integer, Integer> map = new HashMap<>();
int max = 0;
for (int i = 0, j = 0; i < arr.length; ++i) {
if (map.containsKey(arr[i])) {
j = Math.max(j, map.get(arr[i]) + 1);
}
map.put(arr[i], i);
max = Math.max(max, i - j + 1);
}
return max;
}
解法二:我们还可以用一个队列,把元素不停的加入到队列中,如果有相同的元素,就把队首的元素移除,这样我们就可以保证队列中永远都没有重复的元素
public int maxLength(int[] arr) {
//用链表实现队列,队列是先进先出的
Queue<Integer> queue = new LinkedList<>();
int res = 0;
for (int c : arr) {
while (queue.contains(c)) {
//如果有重复的,队头出队
queue.poll();
}
//添加到队尾
queue.add(c);
res = Math.max(res, queue.size());
}
return res;
}
解法三:同样我们还可以使用集合set来代替队列,用两个指针,一个left一个right,如果有重复的就把left指向的给移除(left相当于队首,right相当于队尾)
public int maxLength(int[] arr) {
int maxLen = 0;
Set<Integer> set = new HashSet<>();
int left = 0, right = 0;
while (right < arr.length) {
while (set.contains(arr[right]))
set.remove(arr[left++]);
set.add(arr[right++]);
maxLen = Math.max(maxLen, right - left);
}
return maxLen;
}