Seeker的奇妙求职历险(字节跳动三面)

前言

7月22日晚上8点钟,我进行了字节跳动客户端的第三次面试。说实话,在面试开始之前我还是有点忐忑不安的,走到最后一面了就感觉格外紧张,根据隔壁同学面试的经历反复刷了二叉树的迭代遍历和各种排序的递归和迭代方法(隔壁是实验室的同学三面问了二叉树的迭代中序遍历),不过最后并没有用上。

面试开始

面试官稍微迟到了一小会,简单寒暄过后,就开始了正式的面试。
他首先问我,你C#和Java哪个更加擅长一些?
我回答说Java。
然后他就开始问我关于C#桌面开发相关的内容。

代码混淆的原理

因为之前开发过桌面端的项目,在代码被人反编译之后,我就给桌面端的发布版本进行了代码的混淆,当时用的是一个VS下的免费的代码混淆,所以最后只是对变量名、方法名进行了一个替换,使得代码的可阅读性变得很差,对于原理其实我并不清楚。
所以,当我回答到这里的时候,面试官其实不太满意。
后来我查阅了一下资料,发现常用的代码混淆技术有如下几种:

  • 混淆方法名和变量名:最简单的,只是降低了代码的可读性,还会造成DLL连接的错误。
  • 常量展开:把一些指令的立即数对其进行展开,说白了就是常量折叠的反面。
  • 恒等运算:把nor reg32之类的指令转化为xor reg32,-1
  • 模式替换:用执行结果相同的指令进行替换,可以多次重复。
  • 插入死代码:伪造出一些不会执行的死分支,比如在执行的时候进行条件判断柯西不等式,如果为真则执行真代码。这样的代码也可以让人摸不到头脑。
  • 虚拟机技术:把一部分代码重新编译,并且打包解释器进程序,运行的时候动态解释执行。
  • 打乱代码顺序局部性:改变部分代码块之前的排序。
  • 特殊的控制流模糊化:强行触发异常,然后在异常处理的handle中将程序设置为正常的状态。

参考文章:https://zhuanlan.zhihu.com/p/46247049

Binding的原理

既然做过WPF项目,那么肯定用到了Binding技术(听说这还是一个WPF首创的技术),那么你了解Binding的原理吗?
我说,我们项目是这么用的,巴拉巴拉,但是原理我不太清楚,我猜测他是一个监听者模式,当数据发生变化的时候会发送消息给前端页面,这样就达到了一个实时更新的功能。

原理:
 一个最简单的Binding就是把A的属性绑定到B的属性上,当B的属性变化时,A的属性可以自动更新。这个Binding分两层含义:

A需要监视B属性的变化,当B属性变化时A得到通知。
当收到变化通知时,A要根据B的属性新值来设置自己的属性值。
关于监视B属性变化,这是一个经典的Observer模式,在.net中用event 来表示,如:

b.PropertyChanged += a.HandlePropertyChanged;
void HandlePropertyChanged()
 {
    a.Prop = b.Prop;
 }

关于PropertyChange事件,.net在System.ComponentModel里提供INotifyPropertyChanged接口,里面定义了event PropertyChangedEventHandlerPropertyChanged。通常可被用于数据绑定Model类都要实现INotifyPropertyChanged接口,在属性变化时raise这PropertyChanged事件。
参考文章:https://www.cnblogs.com/umlchina/articles/2067723.html

DLL的原理

你用过DLL吗?知道原理吗?
答:不太清楚。

原理:
静态连接库就是把(lib)文件中用到的函数代码直接链接进目标程序,程序运行的时候不再需要其它的库文件;动态链接就是把调用的函数所在文件模块(DLL)和调用函数在文件中的位置等信息链接进目标程序,程序运行的时候再从DLL中寻找相应函数代码,因此需要相应DLL文件的支持。

静态链接库与动态链接库都是共享代码的方式,如果采用静态链接库,则无论你愿不愿意,lib 中的指令都全部被直接包含在最终生成的 EXE 文件中了。但是若使用 DLL,该 DLL 不必被包含在最终 EXE 文件中,EXE 文件执行时可以“动态”地引用和卸载这个与 EXE 独立的 DLL 文件。静态链接库和动态链接库的另外一个区别在于静态链接库中不能再包含其他的动态链接库或者静态库,而在动态链接库中还可以再包含其他的动态或静态链接库。

参考文章:https://www.cnblogs.com/AI-Algorithms/p/3725696.html

JVM类加载

可能他看我C#掌握的不太好,于是就开始问Java相关的内容。
首先问了我你知道类是怎么加载的吗?
答:五个阶段,每个阶段干了什么大致说了一下。

双亲委派机制

双亲委派机制了解吗?有哪些类加载器?为什么要这么做?
答:原理,责任链模式、4种加载器,保证加载出来类的唯一性,然后详细说了说。

两个Java进程运行在同一个JVM上吗?

其实这个问题我确实不知道,但是我回答说我觉得应该不是,从操作系统层面来说两个用户级进程应该是相互不可见的,而且JVM书上的内存分布中只有一个堆,而不是若干个不同进程的堆,所以我觉得应该是一个Java进程一个JVM。
然后查了一下也确实如此。

共享内存的原理

刚才你说到内存分布对吧,那共享内存你用过吗?
我说我没有用过,但是原理我还是知道的,就是两个进程各自拿出一部分虚拟内存映射到同一块物理内存,这样两个进程就可以对同一块物理内存进行操作。

算法题

到这里大概问了二十多分钟,他说我们来做一道简单点的算法题吧。

数组的最大子数组和

给出一个数组,求这个数组中元素的最大和的子数组。
输入:[1,2,-3,4,5,-6]
输出:[1,2,4,5]
我心想:这好像有点简单,不是把所有的正数加起来吗?

数组的K个元素最大子数组和

当我说了我的想法之后,他说很好,那我再加一个限制条件,要求是K个元素的最大和。
输入:[1,2,-3,4,5,-6]k=2
输出:[4,5]
我说我想把数组进行排序,然后取前K个不为0的正数,这样的时间复杂度是o(nlogn)。

要求保持相对顺序

他说,好的,那我再加一个限制条件,要求子数组的元素相对顺序不变。
输入:[1,2,-3,4,5,-6]k=2
输出:[4,5] 而不能是[5,4]

到这里感觉这道题目就有一些难度了,我思考了一会之后,说了我的想法:
保持一个滑动窗口,当一个新的正数进来之后,移除最小的一个正数,然后把这个元素后面的元素都向前移动一格,然后把新的元素放在最后一格上。
这样的话时间复杂度比较高,最坏的情况是每次都要移动,所以是一个o(nk)的时间复杂度。

他说那你还能进行优化吗?然后提示我用o(2k)的额外空间可以降低复杂度。
最后他看我实在想不到,说你实在不行就用hashmap保存一下数组下标。
那我说:首先保存数组中所有正数的下标,然后排序,取前k个数,然后再对结果数组按照下标排序,这样的话,时间复杂度是(nlogn+klogk)。
面试官觉得我可能实在是想不到了,就说,那你能用代码把你刚才说的任意一种方式实现一下吗?
就写了最后一种方法的代码,用Arrays.sort和lambda表达式写的,所以大概几分钟就写完了。

不过后来我想了想,其实用hashmap保存下标的方式不可行,因为当数组中有重复元素的时候会导致排序出错。
比如:[5,2,3,-4,5,-6]k=4,这样最后由于hashmap会覆盖掉原来的下标导致最后的结果是[2,3,5,5]而不是[5,2,3,5]。所以我到现在都还不知道最好的解法是什么。

感谢陶总给出的最优解,我陶总一枪秒了,有什么好说的。
开辟了一个2n的二维数组用于保存原来的值和下标,然后对值进行排序,然后选取前k个,最后再按下标排序,由于是数组所以不存在重复问题。

public static void fun1(int[] arr, int k){
    int[][] nums = new int[arr.length][2];
    //保存原来的值和下标
    for (int i = 0; i < arr.length; i++) {
        nums[i][0] = arr[i];
        nums[i][1] = i;
    }
    //按值排序
    Arrays.sort(nums, ((o1, o2) -> (o2[0] - o1[0])));
    int[][] sout = Arrays.copyOfRange(nums, 0, k);
    //按下标排序
    Arrays.sort(sout, (o1, o2) -> (o1[1] - o2[1]));
    for (int i = 0; i < sout.length; i++) {
        System.out.print(sout[i][0] + " ");
    }
}

闲聊

写完代码之后,问了我项目中遇到过最大困难是什么?
最近在学校里忙吗?主要在干什么?

后记

总的来说这次面试其实感觉自己发挥的不太好,面试官也说我用过的东西居然不知道原理。
其实说实话我并没有想到会问我C#的东西,所以我并没有准备,之前做项目的时候也确实不求甚解。不过吃一堑长一智,简历上写的东西和技术一定要知道其原理。之后的面试中也会对简历内容进行压缩,然后把一些核心技术的原理给搞明白。
最后,其实我刚面试完的时候面如死灰,感觉这次应该是真凉了,但是没想到第二天上午hr小姐姐告诉我面试通过了,人生的大起大落来的有一些快。
不过还是不能停止学习的脚步,所以说不要停下来啊。


在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/qq_33241802/article/details/107534692
今日推荐