近期某面试汇总以及之后的规划

引言

今年的行情确实如疫情发展得一样,岗位非常少,并且甲方的难度有点难过,大部分都不问项目,而是直接底层了,问得头皮发麻,和去年相比,问的问题都是两个层次,这也导致我迷茫了很长一段时期,因为本身我自己的硬性条件就不是很好,可能要考虑转型,计划从学go变成Java,如果不出意外的话,我也需要拿出跟以前一样的热情去迎接新的挑战了:

面试题总结

哈希表的设计要求和执行过程

要设计一个哈希表首先要做的就是散列函数的计算,通过散列函数就可以将键转换为数组的索引。其实哈希函数的设计是一个非常常见的一个研究方向,就像在我们的网络安全的密码设计的过程中,散列函数就是一个非常重要的理论。

当时被问到这个问题的时候真的是懵的,不过幸好已经提前开始看Java了,说了一通jvm,也不管面试官有没有听懂,反正我自己是理解得不太行。所以在这里看看别人的帖子再总结一下:

哈希表的设计要求(最好有数学公式??):

举个例子:

166 = 1 1 0 2 + 6 1 0 1 + 6 1 0 0 166 = 1* 10^2 + 6 *10^1+ 6*10^0

h a s h ( c o d e ) = ( c B 3 + o B 2 + d B 1 + e B 0 ) % M hash(code) =(c*B^3+o*B^2+d*B^1+e*B^0)\%M

h a s h ( c o d e ) = ( ( ( ( c % M ) B + o ) % M B + d ) % M B + e ) ) % M hash(code) =((((c\%M)*B+o)\%M*B+d)\%M*B+e))\%M

其实左后就准换成为上面公式的样子,其中B表示进制,M表示模的素数。这也只是单类型转换,如果是组合类型,将是:

h a s h ( s t u d e n t ) = ( ( ( s t u d e n t . n a m e % M ) B + s t u d e n t . n u m b e r ) % M B + s t u d e n t . s o c r e ) % M hash(student) = (((student.name\%M)*B + student.number)\%M*B + student.socre)\%M

然后就是三种方法:链地址法(拉链法)、动态空间处理和开放地址法,这里我详细看了下动态空间处理法:

我们上实现的时候把M的值取成了固定值,这个时候我们来分析下他的时间复杂度:

如果放入哈希表中的元素的个数使N,每个地址中存放的元素的个数是N/M的,然后每个地址中存放的是TreeMap,也就是底层是红黑树,对于一个红黑树的查询一个元素的时间复杂度是O(logN/M)的。然而对于哈希表其实是查询的复杂度应该是O(1)的复杂度,因为底层就是数组,直接索引一个数组中的值也就是O(1)的复杂度。

但是这里明显不符合啊?其实就是开辟的空间是固定的导致的,我们需要进行动态空间处理。怎么处理呢?其实就是把和动态数组的处理是一样的。当元素的个数大于阈值的时候就扩大空间,小于阈值时就压缩空间,具体如下:

当平均每个地址承载的元素多过一定程度时就扩容:n/M >= upperTol;

当平均每个地址承载的元素少于一定程度时就缩容:n/M < lowerTol;

然后还可以看看jdk7中对于hashmap中的解释:Java7源码浅析——对HashMap的理解

public class HashMap<K,V>
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
{
 
    /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 16;
 
    /**
     * The maximum capacity, used if a higher value is implicitly specified
     * by either of the constructors with arguments.
     * MUST be a power of two <= 1<<30.
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;
 
    /**
     * The load factor used when none specified in constructor.
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

衍生题:面试中关于HashMap的时间复杂度O(1)的思考

    public V get(Object key) {  
        if (key == null)  
            return getForNullKey();  
        int hash = hash(key.hashCode());  
        for (Entry<K,V> e = table[indexFor(hash, table.length)];  
             e != null;  
             e = e.next) {  
            Object k;  
            if (e.hash == hash && ((k = e.key) == key || key.equals(k)))  
                return e.value;  
        }  
        return null;  
    }  

请讲出常用的设计模式和设计理念

这题问得很笼统,不过在很久之前我因为做了实验楼的一个实验,写了一篇python版的创建型模式,然后大致答到了单例、工厂、装饰器和代理,不过因为太长时间没看,还是接近于想到啥说啥,很混乱,被说理解得有问题确实没啥毛病,但确实琢磨不出来深度原理。。。这里看到一篇帖子就顺手记录一下:

范围 创建型 结构型 行为型
Factory Method(工厂方法) Adapter(类) (适配器) Interpreter(解释器)
Template Method(模版方法)
对象 Abstract Factory(抽象工厂)
Builder(建造者)
Prototype(原型)
Singleton(单例)
Bridge(桥接)
Composite(组合)
Decorator(装饰者)
Façade(外观)
Flyweight(享元)
Proxy(代理)
Chain of Responsibility(职责链)
Command(命令)
Iterator(迭代器)
Mediator(中介者)
Memento(备忘录)
Observer(观察者)
State(状体)
Strategy(策略)
Visitor(访问者)

同时还有六大原则:

同时,我们需要了解到,设计模式的6个基本原则,这也算是本题的设计理念:

  • 1、单一职责原则(Single Responsibility Principle)
  • 2、里氏代换原则(Liskov Substitution Principle)
  • 3、依赖倒转原则(Dependence Inversion Principle)
  • 4、接口隔离原则(Interface Segregation Principle)
  • 5、迪米特法则,又称最少知道原则(Demeter Principle)
  • 6、开闭原则(Open Close Principle)

更多详细的解释可以看 如何通俗理解设计模式及其思想

然而面试肯定不是只有通俗理解,它需要一些项目中理解得更深层次的东西,比如说单例日志类等一系列应用,还有自己的想法,我在答完这个问题后,可能是因为答得很笼统,看起来都在点上,但都被否定了。

HTTP中四次挥手的等待时间

TCP的四次挥手之后,主动方为什么等待2倍最大生命周期(MSL Maximum Segment Lifetime),这个问题我感觉大致达到为什么要有等待时间就OK了,具体的背也没背会。

这最主要是因为两个理由:

1、为了保证客户端发送的最后一个ACK报文段能够到达服务器。 因为这个ACK有可能丢失,从而导致处在LAST-ACK状态的服务器收不到对FIN-ACK的确认报文。服务器会超时重传这个FIN-ACK,接着客户端再重传一次确认,重新启动时间等待计时器。最后客户端和服务器都能正常的关闭。假设客户端不等待2MSL,而是在发送完ACK之后直接释放关闭,一但这个ACK丢失的话,服务器就无法正常的进入关闭连接状态。

2、还可以防止已失效的报文段。 客户端在发送最后一个ACK之后,再经过经过2MSL,就可以使本链接持续时间内所产生的所有报文段都从网络中消失。从保证在关闭连接后不会有还在网络中滞留的报文段去骚扰服务器。

注意:在服务器发送了FIN-ACK之后,会立即启动超时重传计时器。客户端在发送最后一个ACK之后会立即启动时间等待计时器。

numpy和pandas数组有什么区别

百度不到这个题目的答案,可想而知我当时是多么的懵逼。我大概就知道python列表和numpy数组的一个区别,之前 numpy总结与思维导图 一文中大概写了点区别。但pandas和numpy这个问题属实没想明白。当时答得是pandas花费更多时间在表结构可视化上,所以可能会比numpy慢?不知道,如果有大佬懂可以留言或者私信我,谢谢。

restful盛行最本质的原因是什么?

我开始想谈一大堆restful的设计原则:

  1. 每一个URI代表一种资源;
  2. 同一种资源有多种表现形式(xml/json);
  3. 所有的操作都是无状态的。
  4. 规范统一接口。
  5. 返回一致的数据格式。
  6. 可缓存(客户端可以缓存响应的内容)。

然而真正火起来的原因,我没有定论。说的时候也没有上面那样标准,有点想到什么说什么,这个是我的失误,因为今年面试太少,我基本毫无准备就想凭借自己的经验答这类文字题,事实表明是不行的。

面试官点醒,其实是上面第三点的三个字:无状态。 然后根据这个还能扯到微服务和分布式。。。于是我现在写这篇博文的时候,顺带去查到了这篇 深入RESTful无状态原则

因为无状态原则的特性,让RESTful在分布式系统中得到了广泛的应用,它改善了分布式系统的可见性、可靠性以及可伸缩性,同时有效的降低了Client与Server之间的交互延迟。无状态的请求有利于实现负载均衡,在分布式web系统下,有多个可的Server,每个Server都可以处理Client发送的请求。有状态的请求的状态信息只保存在第一次接收请求的Server上,所以后来同一个Client的请求都只能由这台Server来处理,Server无法自由调度请求。无状态请求则完全没有这个限制。其次,无状态请求有较强的容错性和可伸缩性。如果一台服务器宕机,无状态请求可以透明地交由另一台可用Server来处理,而有状态的请求则会因为存储请求状态信息的Server宕机而承担状态丢失的风险。Restful风格的无状态约束要求Server不保存请求状态,如果确实需要维持用户状态,也应由Client负责。

说说你接近两年,做过你比较得意的或者理解得较深的东西

在问这个问题前,还问了一些我项目中出现过的流程还要算法原理,因为我之前做过一点nlp,不知道是失望还是什么原因,问出了这个问题,然后我突然发现我连这个问题都已经回答不了了,没有什么成就,况且那个时候心态已经崩了,我也忘了当时讲的什么,现在也不愿意去回想这个问题,选择性失忆吧。最后我跟面试官坦白了近期的一些焦虑以及我能想到的方向,但这种东西旁人是很难提一些指导性意见的,况且我技术并不过关,不置可否,落荒。。。

结尾

隔了两个多礼拜回来看当时写的东西,本来是可能要见底的一篇私人笔记,是我最后几次之一,记得还清楚。如果现在我选择做测试,那么就永远不会公开了,但很庆幸,我竟然还能做开发,就我这种半桶水,而且很多东西已忘光,又没有准备面试题,近期还被血虐到人有点颓。。。现在准备重新捡起了,很开心还能用一篇博文总结我的失败,我会从这些失败中醒来,继续之前未完的道路,谢谢。

猜你喜欢

转载自blog.csdn.net/submarineas/article/details/105763468