只有程序员看的懂面试圣经|如何拿下编程面试(4)

和树一样,图也是由带子集的结点组成的,但和树不一样的地方在于,这些结点可以有多个父结点,所以可能会形成自环(loop)或者圈(cycle)。除了链接——也被称作边(edges)——之外,两个结点之间可能地有比指针更多的信息,而且可能会有值和权重。边有方向的图被称为有向图,而只有双向指针的图被称为无向图。边上有权重的图被称为加权图。

有三种方法来表示图,但你只要搞清楚邻接矩阵(adjacency matrices)和邻接表(adjacency lists)就行了。你应该了解它们计算的复杂程度、它们需要折衷的地方,以及如何在现实的代码中实现它们。用哪种方法取决于你有的图的类型,比如连接完整的简单图可能用邻接矩阵来实现更好,而稀疏一些的图则可能用邻接表来表示更好。

请注意,如果你是在实现加权图,很可能需要定义一个Edge类。

图论是一个非常宽泛的话题,所以很难知道一个人应该为一场面试去熟悉多少种图论算法,所以我只是列出了我认为可以覆盖90%图论问题的内容:你绝对必须知道该如何遍历一个图(深度优先或者广度优先),以及如何做拓扑排序(topological sorting),你应该知道如何实现迪杰斯特拉(Dijkstra)的最短路径算法(这里有一个制作精巧的视频解释了这一算法),同时也要知道如何实现普里姆(Prim’s)算法。最后,如果你还知道如何实现A搜索算法(Asearchalgorithm),那就更好了。

其他数据结构

使用以上数据结构,你就可能解决绝大多数问题了,但也请尽管在这个部分下留言,为其他读者推荐其他数据结构。

位操作

要想处理位元,你必须先得知道在二进制补码(two’s complement)标记内部,数字是如何表示的——二进制补码和无格式二进制标记是一样的,只是负数要“进行位元翻转之后再加1”。比如要想得到数字-1,你要从用8位二进制整数表示是00000001的1开始。对每一个位元进行翻转之后的结果是11111110,再加上1就是11111111,也就成了二进制补码中的-1。

左移位运算符“<<”会把位元移向左边,用0来补上移走之后的空位。

右移位运算符“>>”会把一个位模式向右移,但当向右移动负数时,它的作用在不同编程语言中也不一样,在Java中,右移位会用符号扩充的办法,用1来填充负数中的空位。

逻辑右移位运算符“>>>”是Java和Javascript中独有的,无论数值是多少,它都用0来填充空位。

设置某一位:可以用按位或运算符(|)。

num |= 1 << x; //这行代码将会设置位元x

清除某一位:可以用按位与运算符(&),并且用取反运算符(~)来屏蔽所有你不想清除的位元。

num &= ~(1 << x); //这会清除位元x

清除一直到i的所有有效位元:

num &= (1 << (i + 1)) -1;

切换某一位元:可以用按位异或运算符(^)

num ^= 1 << x; //这会切换位元x

获得一个位元:对你想检查的位元用按位与

bit = num & (1 << x);

设计模式/面向对象编程

和面向对象编程相关的问题,一般会涉及到设计相关类里的集,以便检验你对面向对象编程的熟悉程度,并了解你是如何架构代码的。你可以使用界面和/或抽象的类来说明,并记住用单例模式(Singleton)、工厂方法模式(Factory)和策略模式(Strategy)来解决这类问题,在编写优雅而可维护的代码方面,它们能对你有长久的助益。

编程应该知道的事情

要知道如何用你正在使用的编程语言来读取和写入文件,并且要知道如何生成随机数。

数学

你并不是在面试数学相关的职位,但考虑到我们被计数和测量的问题所包围,所以有一些数学概念也成了编程面试时关注的东西,比较重要的有质数、进制转换(base conversions)和一些基本的组合数学。

对于质数,要大概知道为什么它们很重要,并且要知道每一个数都可以被分解成质数的和。你还得知道如何实现埃拉托斯特尼筛法(sieve of Eratosthenes)。

对于基本的组合数学,你得知道排列和组合。

排列是对一个集合中的数按照一定的次序或者顺序进行整理。比如对于集合{1,2,3},就有6种排列的方式,也就是(1,2,3)、(1,3,2)、(2,1,3)、(2,3,1)、(3,1,2)和(3,2,1)。n个不同数字的排列方式一共有n!种。

还有一种排列叫部分排列,也就是从n个数字的集合中取出k个不同的元素,然后再进行排序。这种排列可以用下面的公式来表达:

部分排列公式

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/f441ec485446e3810a030f2eaa1f8bd8.html