数据结构面试题2

2020-07-12  本文已影响0人  加油11dd23

1、 找出数组中只出现1次的数,其余数均出现2次,扩展,其余数出现2次以上

位运算中异或的性质:两个相同数字异或=0,一个数和0异或还是它本身。当只有一个数出现一次时,我们把数组中所有的数,依次异或运算,最后剩下的就是落单的数,因为成对儿出现的都抵消了。

 2、单链表判断是否有环(leetcode easy),以及判断环入口

两个指针,一个每次走一步,一个每次走两步,如果有环,两者会相遇。相遇后,让一个指针从头结点再次出发,两个指针每次都走一步,直到相遇点即为环入口。

3、跳台阶问题,每次只能跳1个台阶或者2个台阶,n个台阶共有多少种方式

动态规划 F[n] = F[n-1] + F[n-2]

4、动态规划和带记忆递归的区别

自顶而下和自底而上

5、手撕代码:0-1矩阵的最大正方形

6、平衡二叉树与红黑树区别与联系

平衡二叉树

平衡二叉树又称为AVL树,是一种特殊的二叉排序树。其左右子树都是平衡二叉树,且左右子树高度之差的绝对值不超过1。一句话表述为:以树中所有结点为根的树的左右子树高度之差的绝对值不超过1。将二叉树上结点的左子树深度减去右子树深度的值称为平衡因子BF,那么平衡二叉树上的所有结点的平衡因子只可能是-1、0和1。只要二叉树上有一个结点的平衡因子的绝对值大于1,则该二叉树就是不平衡的。

红黑树:

红黑树是一种二叉查找树,但在每个节点增加一个存储位表示节点的颜色,可以是红或黑(非红即黑)。通过对任何一条从根到叶子的路径上各个节点着色的方式的限制,红黑树确保没有一条路径会比其它路径长出两倍,因此,红黑树是一种弱平衡二叉树,相对于要求严格的AVL树来说,它的旋转次数少,所以对于搜索,插入,删除操作较多的情况下,通常使用红黑树。

性质:

1. 每个节点非红即黑

2. 根节点是黑的;

3. 每个叶节点(叶节点即树尾端NULL指针或NULL节点)都是黑的;

4. 如果一个节点是红色的,则它的子节点必须是黑色的。

5. 对于任意节点而言,其到叶子点树NULL指针的每条路径都包含相同数目的黑节点;

区别:

AVL 树是高度平衡的,频繁的插入和删除,会引起频繁的rebalance,导致效率下降;红黑树不是高度平衡的,算是一种折中,插入最多两次旋转,删除最多三次旋转。

7、请你说一说Top(K)问题

1、直接全部排序(只适用于内存够的情况)

当数据量较小的情况下,内存中可以容纳所有数据。则最简单也是最容易想到的方法是将数据全部排序,然后取排序后的数据中的前K个。

这种方法对数据量比较敏感,当数据量较大的情况下,内存不能完全容纳全部数据,这种方法便不适应了。即使内存能够满足要求,该方法将全部数据都排序了,而题目只要求找出top K个数据,所以该方法并不十分高效,不建议使用。

2、快速排序的变形 (只使用于内存够的情况)

这是一个基于快速排序的变形,因为第一种方法中说到将所有元素都排序并不十分高效,只需要找出前K个最大的就行。

这种方法类似于快速排序,首先选择一个划分元,将比这个划分元大的元素放到它的前面,比划分元小的元素放到它的后面,此时完成了一趟排序。如果此时这个划分元的序号index刚好等于K,那么这个划分元以及它左边的数,刚好就是前K个最大的元素;如果index  > K,那么前K大的数据在index的左边,那么就继续递归的从index-1个数中进行一趟排序;如果index < K,那么再从划分元的右边继续进行排序,直到找到序号index刚好等于K为止。再将前K个数进行排序后,返回Top K个元素。这种方法就避免了对除了Top K个元素以外的数据进行排序所带来的不必要的开销。

3、最小堆法

这是一种局部淘汰法。先读取前K个数,建立一个最小堆。然后将剩余的所有数字依次与最小堆的堆顶进行比较,如果小于或等于堆顶数据,则继续比较下一个;否则,删除堆顶元素,并将新数据插入堆中,重新调整最小堆。当遍历完全部数据后,最小堆中的数据即为最大的K个数。

4、分治法

将全部数据分成N份,前提是每份的数据都可以读到内存中进行处理,找到每份数据中最大的K个数。此时剩下N*K个数据,如果内存不能容纳N*K个数据,则再继续分治处理,分成M份,找出每份数据中最大的K个数,如果M*K个数仍然不能读到内存中,则继续分治处理。直到剩余的数可以读入内存中,那么可以对这些数使用快速排序的变形或者归并排序进行处理。

5、Hash法

如果这些数据中有很多重复的数据,可以先通过hash法,把重复的数去掉。这样如果重复率很高的话,会减少很大的内存用量,从而缩小运算空间。处理后的数据如果能够读入内存,则可以直接排序;否则可以使用分治法或者最小堆法来处理数据。

8、请你回答一下栈和堆的区别,以及为什么栈要快

堆和栈的区别:

堆是由低地址向高地址扩展;栈是由高地址向低地址扩展

堆中的内存需要手动申请和手动释放;栈中内存是由OS自动申请和自动释放,存放着参数、局部变量等内存

堆中频繁调用malloc和free,会产生内存碎片,降低程序效率;而栈由于其先进后出的特性,不会产生内存碎片

堆的分配效率较低,而栈的分配效率较高

栈的效率高的原因:

栈是操作系统提供的数据结构,计算机底层对栈提供了一系列支持:分配专门的寄存器存储栈的地址,压栈和入栈有专门的指令执行;而堆是由C/C++函数库提供的,机制复杂,需要一些列分配内存、合并内存和释放内存的算法,因此效率较低。

9、请你说一说小根堆特点

堆是一棵完全二叉树(如果一共有h层,那么1~h-1层均满,在h层可能会连续缺失若干个右叶子)。

1)小根堆

若根节点存在左子女则根节点的值小于左子女的值;若根节点存在右子女则根节点的值小于右子女的值。

2)大根堆

若根节点存在左子女则根节点的值大于左子女的值;若根节点存在右子女则根节点的值大于右子女的值。

10、一个长度为N的整形数组,数组中每个元素的取值范围是[0,n-1],判断该数组否有重复的数,请说一下你的思路并手写代码

把每个数放到自己对应序号的位置上,如果其他位置上有和自己对应序号相同的数,那么即为有重复的数值。时间复杂度为O(N),同时为了节省空间复杂度,可以在原数组上进行操作,空间复杂度为O(1)

11、 请你回答一下Array&List, 数组和链表的区别

数组的特点:

数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。数组的插入数据和删除数据效率低,插入数据时,这个位置后面的数据在内存中都要向后移。删除数据时,这个数据后面的数据都要往前移动。但数组的随机读取效率很高。因为数组是连续的,知道每一个数据的内存地址,可以直接找到给地址的数据。如果应用需要快速访问数据,很少或不插入和删除元素,就应该用数组。数组需要预留空间,在使用前要先申请占内存的大小,可能会浪费内存空间。并且数组不利于扩展,数组定义的空间不够时要重新定义数组。

链表的特点:

链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。比如:上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以了。如果应用需要经常插入和删除元素你就需要用链表数据结构了。不指定大小,扩展方便。链表大小不用定义,数据随意增删。

各自的优缺点

数组的优点:

1. 随机访问性强

2. 查找速度快

数组的缺点:

1. 插入和删除效率低

2. 可能浪费内存

3. 内存空间要求高,必须有足够的连续内存空间。

4. 数组大小固定,不能动态拓展

链表的优点:

1. 插入删除速度快

2. 内存利用率高,不会浪费内存

3. 大小没有固定,拓展很灵活。

链表的缺点:

不能随机查找,必须从第一个开始遍历,查找效率低

12、请你来介绍一下各种排序算法及时间复杂度

见 常用排序算法总结

13、请问快排的时间复杂度最差是多少?什么时候时间最差

O(N2),元素本来倒序排列用时最多。

在快速排序的早期版本中呢,最左面或者是最右面的那个元素被选为枢轴,那最坏的情况就会在下面的情况下发生啦:

1)数组已经是正序排过序的。 (每次最右边的那个元素被选为枢轴)

2)数组已经是倒序排过序的。 (每次最左边的那个元素被选为枢轴)

3)所有的元素都相同(1、2的特殊情况)

因为这些案例在用例中十分常见,所以这个问题可以通过要么选择一个随机的枢轴,或者选择一个分区中间的下标作为枢轴,或者(特别是对于相比更长的分区)选择分区的第一个、中间、最后一个元素的中值作为枢轴。有了这些修改,那快排的最差的情况就不那么容易出现了,但是如果输入的数组最大(或者最小元素)被选为枢轴,那最坏的情况就又来了。

快速排序,在最坏情况退化为冒泡排序,需要比较O(n2)次(n(n - 1)/2次)。

14、请问稳定排序哪几种?

基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序

15、请你来说一说hash表的实现

hash表的实现主要包括构造哈希和处理哈希冲突两个方面:

对于构造哈希来说,主要包括直接地址法、平方取中法、除留余数法等。

对于处理哈希冲突来说,最常用的处理冲突的方法有开放定址法、再哈希法、链地址法、建立公共溢出区等方法。SGL版本使用链地址法,使用一个链表保持相同散列值的元素。

16、判断一个链表是否为回文链表,说出你的思路并手写代码

思路:使用栈存储链表前半部分,然后一个个出栈,与后半部分元素比较,如果链表长度未知,可以使用快慢指针的方法,将慢指针指向的元素入栈,然后如果快指针指向了链表尾部,此时慢指针指向了链表中间

17、 给你一个字符串,找出第一个不重复的字符,如“abbbabcd”,则第一个不重复就是c

使用哈希的思想,建立256个bool数组array,初始都为false,从头开始扫描字符串,扫到一个,将以其ascii码为下标的元素置true。例如扫描到A的时候,执行:array['A']=true。第二边扫描,扫到一个字母就以其ascii码为下标,去array数组中看其值,如果是true,返回改字母,如果是false,继续扫描下一个字母。

上一篇下一篇

猜你喜欢

热点阅读