阿里篇——面试 - Go语言中文社区

阿里篇——面试


阿里面试

题目:NFS 和 SMB 是最常见的两种 NAS(Network Attached Storage)协议,当把一个文件系统同时通过 NFS 和 SMB 协议共享给多个主机访问时,以下哪些说法是错误的:(多选)

A. 不可能有这样的操作,即把一个文件系统同时通过 NFS 和 SMB协议共享给多个主机访问。

B. 主机 a 的用户通过NFS 协议创建的文件或者目录,另一个主机 b的用户不能通过 SMB 协议将其删除。

C. 在同一个目录下,主机 a 通过 NFS 协议看到文件 file.txt,主机b 通过 SMB 协议也看到文件 file.txt,那么它们是同一个文件。

D. 主机 a 通过 NFS 协议,以及主机 b 通过 SMB 协议,都可以通过主机端的数据缓存,提升文件访问性能。

参考答案:A,B,C

ConcurrentHashMap原理,JDK1.8都有什么新特性
ConcurrentHashMap 的实现方式是锁桶。 CocurrentHashMap 将hash表分为16个桶(默认值),诸如诸如get,put,remove等常用操作只锁当前需要用到的桶。试想,原来只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。ConcurrentHashMap是线程安全的:JDK1.7版本: 容器中有多把锁,每一把锁锁一段数据,这样在多线程访问时不同段的数据时,就不会存在锁竞争了,这 样便可以有效地提高并发效率。这就是ConcurrentHashMap所采用的"分段锁"思想,见下图:

在这里插入图片描述
每一个segment都是一个HashEntry<K,V>[] table, table中的每一个元素本质上都是一个HashEntry的单向队列(原理和hashMap一样)。比如table[3]为首节点,table[3]->next为节点1,之后为节点2,依次类推。
JDK1.8版本:做了2点修改,见下图:

取消segments字段,直接采用transient volatile HashEntry<K,V>[] table保存数据,采用table数组元素作为锁,从而实现了对每一行数据进行加锁,并发控制使用Synchronized和CAS来操作
将原先table数组+单向链表的数据结构,变更为table数组+单向链表+红黑树的结构.

原文链接:https://blog.csdn.net/weixin_43185598/article/details/87938882

jdk1.8 的新特性: lambda 表达式,方法引用以及多重Annotation ,API 集成,流式编程,函数接口,Map以及全新日期。

HBase底层数据存储的结构,
java内存模型分为了几块区域?元空间里有些啥?

java 虚拟机主要分为以下一个区:
方法区:

  1. 有时候也成为永久代,在该区内很少发生垃圾回收,但是并不代表不发生 GC,在这里
    进行的 GC 主要是对方法区里的常量池和对类型的卸载
  2. 方法区主要用来存储已被虚拟机加载的类的信息、常量、静态变量和即时编译器编译后
    的代码等数据。
  3. 该区域是被线程共享的。
  4. 方法区里有一个运行时常量池,用于存放静态编译产生的字面量和符号引用。该常量池
    具有动态性,也就是说常量并不一定是编译时确定,运行时生成的常量也会存在这个常量
    池中。
    虚拟机栈:
  5. 虚拟机栈也就是我们平常所称的栈内存,它为 java 方法服务,每个方法在执行的时候都

对象创建方法,对象的内存分配,对象的访问定位。
new 一个对象

jdk hashmap 底层存储?红黑树的特点,为啥不用数组用红黑树?

6.数据库用过么?用的啥数据库,mysql用的啥引擎?为啥数据库底层用B+树不用红黑树?

JVM内存模型了解不,是否有过调优经验(大互联公司)
题目:MySQL 的数据如何恢复到任意时间点?

参考答案:恢复到任意时间点以定时的做全量备份,以及备份增量的 binlog 日志为前提。恢复到任意时间点首先将全量备份恢复之后,再此基础上回放增加的 binlog 直至指定的时间点。

NIO 知道么? nio 底层调用了啥? 啥是非阻塞IO?

string类的用法,string a=Hello string a = new string(hello)创建的流程

string类的用法,string a=Hello string a = new string(hello)创建的流程
题目:从 innodb 的索引结构分析,为什么索引的 key 长度不能太长?

参考答案:key 太长会导致一个页当中能够存放的 key 的数目变少,间接导致索引树的页数目变多,索引层次增加,从而影响整体查询变更的效率。

对象存在java内存的那块区域里面
多线程,AtomicInteger底层用的啥?cas的原理,AtomicInteger用了Voliate么?voliate的原理,变量加Voliate被修改了其他线程能立刻知道么?
题目:给定一个二叉搜索树(BST),找到树中第 K 小的节点。

参考答案:

  • 考察点

基础数据结构的理解和编码能力
递归使用

说明:

如果按照中序遍历的顺序遍历一棵二叉搜索树,遍历序列的数值是递增排序的。上图中的二叉搜索树的中序遍历序列为{2,3,4,5,6,7,8},因此,只需要用中序遍历算法遍历一棵二叉搜索树,就很容易找出它的第k大结点。

?
public class Demo1 {
class BinaryTreeNode{
int val;
BinaryTreeNode left;
BinaryTreeNode right;
public BinaryTreeNode(int val) {
this.val = val;
}

}
public static void main(String[] args) {
    Demo1 demo = new Demo1();
    BinaryTreeNode root = demo.new BinaryTreeNode(5);
    BinaryTreeNode a = demo.new BinaryTreeNode(3);
    BinaryTreeNode b = demo.new BinaryTreeNode(7);
    BinaryTreeNode c = demo.new BinaryTreeNode(2);
    BinaryTreeNode d = demo.new BinaryTreeNode(4);
    BinaryTreeNode e = demo.new BinaryTreeNode(6);
    BinaryTreeNode f = demo.new BinaryTreeNode(8);
    
    root.left = a;
    root.right = b;
    a.left = c;
    a.right = d;
    b.left = e;
    b.right = f;
    
    BinaryTreeNode k = KthNode(root,3);
    System.out.println(k.val);
}

static int index=0;

static BinaryTreeNode KthNode(BinaryTreeNode pRoot,int k) {
    if(pRoot==null || k<=0)
        return null;
    return getKthNode(pRoot,k);
}

private static BinaryTreeNode getKthNode(BinaryTreeNode pRoot,int k) {
    BinaryTreeNode KthNode = null;
    if(pRoot.left != null)//如果该节点有左孩子,就一直递归到左叶子节点
        KthNode = getKthNode(pRoot.left,k);
    if(KthNode==null) {
        index++;  //中序遍历的计数
        if(k==index)
            KthNode = pRoot; 
    }
    
    if(KthNode==null && pRoot.right!=null)
        //如果该节点有右孩子,就递归到右孩子
        KthNode = getKthNode(pRoot.right,k);
    
    return KthNode;
    
}

}

题目:给定一个链表,删除链表的倒数第 N 个节点,并且返回链表的头结点。

? 示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明:
给定的 n 保证是有效的。
要求:
只允许对链表进行一次遍历。

参考答案:

我们可以使用两个指针而不是一个指针。第一个指针从列表的开头向前移动 n+1 步,而第二个指针将从列表的开头出发。现在,这两个指针被 n 个结点分开。我们通过同时移动两个指针向前来保持这个恒定的间隔,直到第一个指针到达最后一个结点。此时第二个指针将指向从最后一个结点数起的第 n 个结点。我们重新链接第二个指针所引用的结点的 next 指针指向该结点的下下个结点。

参考代码:

?
public ListNode removeNthFromEnd(ListNode head, int n)
{
ListNode dummy = new ListNode(0);

dummy.next = head;
ListNode first = dummy;
ListNode second = dummy;
// Advances first pointer so that the gap between first
and second is n nodes apart
for (int i = 1; i <= n + 1; i++) {
    first = first.next;
}
// Move first to the end, maintaining the gap
while (first != null) {
    first = first.next;
    second = second.next;
}
second.next = second.next.next;
return dummy.next;

}
?
复杂度分析:

时间复杂度:O(L),该算法对含有 L 个结点的列表进行了一次遍历。因此时间复杂度为 O(L)。
空间复杂度:O(1),我们只用了常量级的额外空间。

题目:给定一个整数数组和一个整数,返回两个数组的索引,这两个索引指向的数字的加和等于指定的整数。需要最优的算法,分析算法的空间和时间复杂度

参考答案:

public int[] twoSum(int[] nums, int target) {
if(nums==null || nums.length<2)
return new int[]{0,0};

HashMap<Integer, Integer> map = new HashMap<Integer, Integer>();
for(int i=0; i<nums.length; i++){
    if(map.containsKey(nums[i])){
        return new int[]{map.get(nums[i]), i};
    }else{
        map.put(target-nums[i], i);
    }
}

return new int[]{0,0};

}
分析:空间复杂度和时间复杂度均为 O(n)

问题:关于 epoll 和 select 的区别,哪些说法是正确的?(多选)

A. epoll 和 select 都是 I/O 多路复用的技术,都可以实现同时监听多个 I/O 事件的状态。

B. epoll 相比 select 效率更高,主要是基于其操作系统支持的I/O事件通知机制,而 select 是基于轮询机制。

C. epoll 支持水平触发和边沿触发两种模式。

D. select 能并行支持 I/O 比较小,且无法修改。

参考答案:A,B,C

【延伸】那在高并发的访问下,epoll使用那一种触发方式要高效些?当使用边缘触发的时候要注意些什么东西?

假设有一亿个用户每个用户订阅了一个手机闹铃闹铃类型不同,都是7点钟的闹铃,如何保证7点时数据库的负载最小,简述你的方案,
public class SynchronousQueueQuiz {
public static void main(String[] args) throws Exception {
    BlockingQueue<Integer> queue = new
    SynchronousQueue<>();
    System. out .print(queue.offer(1) + " ");
    System. out .print(queue.offer(2) + " ");
    System. out .print(queue.offer(3) + " ");
    System. out .print(queue.take() + " ");
    System. out .println(queue.size());
}

}
?
A. true true true 1 3

B. true true true (阻塞)

C. false false false null 0

D. false false false (阻塞)

参考答案:D

问题:如何实现一个高效的单向链表逆序输出?

参考答案:下面是其中一种写法,也可以有不同的写法,比如递归等。供参考。

public class MyLinkedList {

public int data;
public MyLinkedList next;

public MyLinkedList(int data) {
    this.data=data;
    this.next=null;
}

public MyLinkedList() {
    this.data=-1;
    this.next=null;
    
}
题目:已知 sqrt (2)约等于 1.414,要求不用数学库,求 sqrt (2)精确到小数点后 10 位。

参考答案:

  • 考察点

基础算法的灵活应用能力(二分法学过数据结构的同学都知道,但不一定往这个方向考虑;如果学过数值计算的同学,应该还要能想到牛顿迭代法并解释清楚)
退出条件设计
二分法

  1. 已知 sqrt(2)约等于 1.414,那么就可以在(1.4, 1.5)区间做二分

查找,如:
a) high=>1.5
b) low=>1.4
c) mid => (high+low)/2=1.45
d) 1.45*1.45>2 ? high=>1.45 : low => 1.45

public class Main {
public static void main(String[] args) {
//手写二分估值
System.out.println(myCalculate(1.4,1.4,1.5));
//调用函数输出
//System.out.println("----------sqrt= "+Math.sqrt(2.0));
}
//根号2约等于 1.414
private static double myCalculate(double ans,double low,double high) {
double mid = 0;
// 二分法,结束条件:差值小于等于1e-10即可
while(high-low>1e-10){

         mid = (high+low)/2.0;
       // System.out.println("-----------mid= "+mid+"  mid*mid= "+mid*mid);
        //二分,逐步向中间值收拢
        if(mid*mid <= 2.0){
            low=mid;
        }
        else{
            high=mid;
        }
        
    }
    
    return mid;
}

}
牛顿迭代法

1.牛顿迭代法的公式为:

xn+1 = xn-f(xn)/f’(xn)

对于本题,需要求解的问题为:f(x)=x2-2 的零点

EPSILON = 0.1 ** 10
def newton(x):
if abs(x ** 2 - 2) > EPSILON:
return newton(x - (x ** 2 - 2) / (2 * x))
else:
return x

知道spring AOP是如何实现的么,动态代理和CGlib分别是如何实现的
版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/weixin_43501566/article/details/114601964
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢