一面 80min
- http和https的区别
- https用到了哪些加密技术
- http使用到了哪些其他协议?
- 讲一下dns过程。给一个网址www.bytedance.com,dns服务器如何逐级解析的
- 讲一下tcp四次挥手,time-wait干嘛的,close-wait干嘛的,在哪一个阶段
- Tcp粘包拆包问题
- TCP拥塞控制与流量控制区别
- Mysql了解吗,讲一下事务,那mysql是如何保证ACID的呢(答了undo-log,redo-log,加锁,mvcc),那讲一下MVCC
- 快照读在提交读和可重复读级别下有什么区别
- 你提到了隐藏列有一个DB_ROW_ID,是干嘛的?那假设有10个update,到第九个回滚了,DB_ROLL_PTR如何做的,那提交了是否更新DB_ROLL_PTR?
- 讲一下索引及其底层,非叶子节点存储的是什么,只有b+树索引吗?(MEMORY是hash索引)
- 算法题:给定一个字符串数组[“hello”,”max”,”aello”,”world”],search(String s),判断字符串数组中是否存在一个字符串s1使得:s修改1个字符变为s1
public class _修改字符 {
private static String[] strs;
public static void main(String[] args) {
strs = new String[]{"hello", "max", "aello", "world"};
String s = "bello";
boolean find = new _修改字符().search(s);
System.out.println(find == true ? "存在" : "不存在");
}
public boolean search(String s){
for (int i = 0; i < strs.length; i++){
// 用于标记不相同字符的个数
int one = 0;
// 如果待修改的字符串与目标字符串的长度不相同,则跳过后续判断
if (strs[i].length() != s.length()) continue;
for (int j = 0; j < strs[i].length(); j++){
if (s.charAt(j) != strs[i].charAt(j)){
if (one == 0){
// 对于第一个不相同的字符,个数+1
one++;
} else {
// 不相同的字符个数超过一个,直接退出循环
one++;
break;
}
}
}
/**
如果相同的字符串也算的话,就相当于不动,比如字符'a'修改为字符'a',那么可以修改一下下
面的判断,改为 if (one <= 1) return true;一样可以实现功能
*/
if (one == 1) return true; // 如果当前字符串与目标字符串只有一个不相同,则找到
}
// 循环结束也没有找到修改一次可以变为目标字符串的字符串
return false;
}
}
- 算法题:二维数组,从左往右递增,从上到下递增,有重复数字,找一个数字是否存在于数组中。
public class _二维数组查找数字 {
public static void main(String[] args) {
int[][] nums = {{1, 2, 3, 3, 3, 4, 5, 8},
{2, 3, 4, 4, 4, 6, 6, 9},
{4, 4, 4, 5, 5, 14, 15, 15},
{5, 8, 11, 12, 12, 15, 20, 20}};
int[] f = new int[25];
for (int i = 0; i < 25; i++){
f[i] = i;
}
for (int i = 0; i < 25; i++) {
System.out.println(i + " = " + new _二维数组查找数字().find2(nums, i));
}
}
// 暴力解法,时间复杂度O(n^2)
public boolean find(int[][] nums, int k){
for (int i = 0; i < nums.length; i++) {
for (int j = 0; j < nums[0].length; j++) {
if (nums[i][j] == k){
return true;
}
}
}
return false;
}
// 优化,基于二分思想,时间复杂度降至O(n)
public boolean find2(int[][] nums, int k){
int row = 0, col = nums[0].length - 1;
while (row < nums.length && col >= 0){
if (nums[row][col] == k){
return true;
} else if (nums[row][col] > k){
col--;
} else {
row++;
}
}
return false;
}
}
二面 70min
- 用户自己写一个String类,会发生什么?
- Sleep()和wait()的区别?
- Object类里有哪些方法?
- 那讲一下equals()与hashcode(),什么时候重写,为什么重写,怎么重写?
- 给一道题,判断输出。
- tcp四次挥手,time-wait
- http状态码有哪些(1xx-5xx),那讲一下301与302的区别
- 讲一下Mysql聚集索引与非聚集索引,主键索引使用int与string有啥区别,你刚才说了索引底层b+树的结构,那么使用String会不会影响到这个结构
- 算法题:找出数字字符串中最长的连续上升子序列(连续上升:前后两数之差为1)(LeetCode 300变种)
public class _最长上升子序列_前后相差1 {
public static void main(String[] args) {
String s = "23426457829828";
System.out.println(new _最长上升子序列_前后相差1().findLongestSequence(s));
}
public String findLongestSequence(String s){
int n = s.length();
int[] dp = new int[n];
Arrays.fill(dp, 1);
int len = 1;
for (int i = 1; i < n; i++){
char c = s.charAt(i);
for (int j = 0; j < i; j++){
char pre = s.charAt(j);
if (c - pre == 1){
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
len = Math.max(len, dp[i]);
}
char[] res = new char[len];
for (int i = n - 1; i >= 0; i--){
if (len == dp[i]){
res[--len] = s.charAt(i);
}
}
return new String(res);
}
}
三面 50min
- 项目(你的哪些技术能用到未来的工作上)
- Java多态,如何实现?动态绑定
- Hashmap底层,扩容机制,为什么到8转为红黑树,装载因子为什么0.75,你自己设计一个hashmap,如何确定装载因子
- Redis作为缓存的基本使用,redis数据结构及底层(c的char[]和redis String有啥区别)
- MySQL性能调优;为什么不用select *
- 算法1:arr[]数组,n个奇数,n个偶数,重排,奇数位置是奇数,偶数位置是偶数(从0开始),空间复杂度O(1),时间复杂度O(n)
void oddEven1(int a[],int left,int right)
{
int i=left,j = right;
int tmp = 0;
while(i<j){
while(i<=right && a[i] % 2 == 0)
i++;
while(j>=left && a[j] % 2 == 1)
j--;
if(i<j)
tmp = a[i],a[i] = a[j], a[j] = tmp;
}
j = left + (right - left)/2;
for(i=left+1;i <=j;i += 2)
tmp = a[i],a[i] = a[right - i],a[right - i] = tmp;
}
void oddEven2(int a[], int left,int right)
{
int i = left,j = right;
int tmp = 0;
while(i<=right){
while(i<= right)
if(i % 2 == 0 && a[i] % 2 ==1)
break;
else
i++;
while(j>=left)
if(j % 2 == 1 && a[j] % 2 == 0)
break;
else
j--;
if(i<=right && j>= left)
tmp = a[i],a[i] = a[j],a[j] = tmp;
}
}
- 算法2:判断数组arr[]中是否存在2个数的异或为k(时间复杂度最优)
public class _判断数组中是否存在异或值为k {
public static void main(String[] args) {
int[] nums = {13, 322, 1, 3, 2, 5, 6,
7, 8, 18, 19, 32, 64, 33};
int[] res = new _判断数组中是否存在异或值为k().findXor2(nums,8);
if (res.length == 2){
System.out.println(Arrays.toString(res));
} else {
System.out.println("不存在");
}
}
// 暴力解法, 时间复杂度O(n^2)
public int[] findXor(int[] nums, int k){
for (int i = 0; i < nums.length; i++){
for (int j = i + 1; j < nums.length; j++){
if ((nums[i] ^ nums[j]) == k){
return new int[]{nums[i], nums[j]};
}
}
}
return new int[0];
}
// 利用哈希表优化,时间复杂度O(n)
public int[] findXor2(int[] nums, int k){
Set<Integer> set = new HashSet<>();
for (int num : nums){
if (set.contains(num ^ k)){
return new int[]{num, num ^ k};
}
set.add(num);
}
return new int[0];
}
}
- 反问:部门业务?
四面 54min
- 项目
- 进程与线程区别,进程通信方式,说一下socket,socket在本机和在网络通信区别
- 多进程与多线程的区别以及使用场景
- 算法题:之字型打印二叉树
解:以下面这棵树为例
public class _之字形打印二叉树 {
// 定义树的节点
static class TreeNode{
int val;
TreeNode left;
TreeNode right;
public TreeNode(){
this.val = 0;
this.left = null;
this.right = null;
}
public TreeNode(int val) {
this.val = val;
this.left = null;
this.right = null;
}
}
public static void main(String[] args) {
List<List<Integer>> result = new ArrayList<List<Integer>>();
// 建树
TreeNode root = new TreeNode(5);
TreeNode p1 = root.left = new TreeNode(3);
TreeNode p2 = root.right = new TreeNode(4);
p1.left = new TreeNode(1);
p2.left = new TreeNode(2);
p2.right = new TreeNode(8);
new _之字形打印二叉树().printTree(root, result);
System.out.println("result = " + result);
}
public List<List<Integer>> printTree(TreeNode root, List<List<Integer>> result){
// 层次遍历的思想,利用队列
Deque<TreeNode> queue = new LinkedList<>();
queue.offer(root);
// 控制方向
boolean direction = false;
while (!queue.isEmpty()){
// 记录当前层的节点个数
int size = queue.size();
List<Integer> list = new ArrayList<>();
// 一个while循环走完就是一层的遍历结构
while (size-- > 0){
root = queue.poll();
list.add(root.val);
// 左节点不为空,加入队列
if (root.left != null){
queue.offer(root.left);
}
// 右节点不为空,加入队列
if (root.right != null){
queue.offer(root.right);
}
}
// 每隔一层,反方向遍历该层
if (direction){
Collections.reverse(list);
}
// 每遍历一层变换方向
direction = !direction;
result.add(list);
}
return result;
}
}
输出结果如下:
- 场景题目:设计王者荣耀战力排行榜,显示某区服所有玩家战力排行情况,以及我自己的战力排行情况
- 反问
五面 35min
- 项目
- 讲一下https,为什么要先使用非对称加密,那非对称加密不能保证安全性吗?(能)
- 讲一下http,请求头,状态码
- 现在我们视频面试用到哪些协议(DNS,HTTP,HTTPS,TCP,UDP),UDP用在哪里
- 讲一下你了解的对称加密算法和非对称加密算法(DES,AES,RSA),非对称加密如何保证它的安全性(数论大数分解)
- xss攻击、cors攻击原理
- Mysql存储引擎的作用,事务隔离级别,分别存在什么问题
- Java如何保证多线程安全
- I/O多路复用讲一下,epoll优势在哪,为什么,epoll水平触发与边缘触发
- 算法题:二维数组顺时针旋转90度
public class _二维数组顺时针旋转90度 {
public static void main(String[] args) {
int[][] nums = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
print(nums);
System.out.println();
// nums = rotate1(nums);
// print(nums);
// System.out.println();
rotate2(nums);
print(nums);
System.out.println();
}
// 该方法开辟了一个二维数组,做起来相对容易,但空间复杂度较高
public static int[][] rotate1(int[][] matrix){
int m = matrix.length;
int n = matrix[0].length;
int[][] array = new int[m][n];
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
array[i][j] = matrix[n - j - 1][i];
}
}
return array;
}
// 进一步优化,原地旋转
public static void rotate2(int[][] matrix){
int m = matrix.length;
int n = matrix[0].length;
// 先将数组的上半部和下半部进行交换
for (int i = 0; i < m / 2; i++){
for (int j = 0; j < n; j++){
int tmp = matrix[i][j];
matrix[i][j] = matrix[m - i - 1][j];
matrix[m - i - 1][j] = tmp;
}
}
// 交换完后对数组进行转置,这里只能对上三角或下三角进行交换
// 操作, 不然数组又变回去了,不能实现转置操作
for (int i = 0; i < m; i++){
for (int j = 0; j < i; j++){
int tmp = matrix[i][j];
matrix[i][j] = matrix[j][i];
matrix[j][i] = tmp;
}
}
}
public static void print(int[][] matrix){
for (int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[0].length; j++){
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
}
}
- 有实习经历吗?为什么不实习?
- 未来职业规划
- 讲一个你最有成就感的事(社团+科研)
- 说一个自己的优缺点
- 反问