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

引言

今年的行情确实如疫情发展得一样,岗位非常少,并且甲方的难度有点难过,大部分都不问项目,而是直接底层了,问得头皮发麻,和去年相比,问的问题都是两个层次,这也导致我迷茫了很长一段时期,因为本身我自己的硬性条件就不是很好,可能要考虑转型,计划从学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 166=1102+6101+6100

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 hash(code)=(cB3+oB2+dB1+eB0)%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 hash(code)=((((c%M)B+o)%MB+d)%MB+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 hash(student)=(((student.name%M)B+student.number)%MB+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,不知道是失望还是什么原因,问出了这个问题,然后我突然发现我连这个问题都已经回答不了了,没有什么成就,况且那个时候心态已经崩了,我也忘了当时讲的什么,现在也不愿意去回想这个问题,选择性失忆吧。最后我跟面试官坦白了近期的一些焦虑以及我能想到的方向,但这种东西旁人是很难提一些指导性意见的,况且我技术并不过关,不置可否,落荒。。。

结尾

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

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

submarineas

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值