剑指offer面试题总结

http://www.aachin.info/tech/%E5%89%91%E6%8C%87offer%E9%9D%A2%E8%AF%95%E9%A2%98%E6%80%BB%E7%BB%93%EF%BC%881%EF%BC%89/

面试题3:查找排序二维数组

面试题4:替换空格为%20

扩展1-复制排序数组B至尾部有足够空余空间的排序数组A。  (我记得我最近一次感叹逆序思路的时候就是这道题,替换空格也在CC上有)

面试题5:从尾到头打印链表

看到题的时候还是能想到用栈的。 不过书中说看到栈要联想到递归,这句话很有道理。

虽然递归显然没有用栈的空间效率高,还有栈溢出的危险什么的,但是不失为一种比较奇特的思路,而且代码看上去很高级。

面试题6:通过中序遍历和前序遍历的序列重建二叉树

这道题和序列化树那道题还蛮像的,最近考过的话要多注意下。

面试题7:两个栈实现队列。或两个队列实现栈。

也是CC原题

不过这里的解决方案涉及了关于泛型方面的知识。如果是要设计数据结构的话,可以多考虑利用泛型的。

还有一点是,我有点太拘泥原子操作了。  认定了pop()操作一定要从stack1开始检查。 其实检查stack2是不是非空,就可以省去每次把stack2中的东西倒回stack1的操作。

面试题8:旋转的排序数组的最小数字

虽然是二分查找的一个变体,但是变体也要稍微注意下各种异常处理。

还有递归时(或者还没开始递归时),头已经小于尾了,那就直接返回头。  因为毕竟不是查找。 而是找最小。

面试题9:费波纳茨数列

记得MIT那个算法视频讲分治的时候就是用的这个例子。

普通递归,(就是开始学递归的时候的例子,除了阶乘,就是这货了)。

然后普通迭代,这个就是两个指针然后累加而已。

然后第三种办法是用一个哈希表吧已经有的状态缓存起来,避免重复计算。  (hackerrank上那倒阶乘和组合的题我也这么用的,,可惜还是没达到他的要求,大数的阶乘真的很慢)。

迭代算是自底向上吧,递归自然是自顶向下了。  所以要是感觉自顶向下很浪费时间空间的话,,那估计转化成迭代差不多吧。  或者是用哈希表那个辅助空间。

对于青蛙跳台阶的那个应用还是蛮有思考余地的,主要是对问题的抽象。

面试题10:二进制中1的个数

右移一位和除以二的结果是一样的,但是位运算的效率要高很多。

位运算的边界条件为负数的时候。

跟2相关的运算可以考虑位与运算的思路。

把整数减去1和本身做位运算,是把整数最后边的1变成零。  传说是条很有用的结论。

========================================================================================

中间插一句:浮点数比较的时候最好不用==. 会有损失精度的问题。

再插一句,关于边界条件测试,整数要考虑位数问题,比如要用int啊,long啊,还是终极杀手BigInteger什么的。

========================================================================================

面试题11:数值的整数次方

其实我有考虑到把这个拆开成小部分,然后再合拢,有点分治的意思。

不过右移一位等于/2这个想法还是挺帅,还有边界啊,错误条件什么的。

计算题一定要考虑除以0的异常什么的。

面试题12:打印1到n位的最大数

碰到n的时候,要考虑大数问题。要是不能用BigInteger就得考虑自己实现个。

另外一种解法是用递归实现全排列。   想当年排列组合多容易的题,,好久没练习然后脱离那个环境倒是没那么灵活了。  我会说我当年真的学得差么然后高考还不是重点我也没太在乎么。

面试题13:O(1)时间删除链表节点

 删除链表时要考虑传值还是传引用。  传值无论如何得遍历,O(1)只能靠hash表来存储。  如果是传引用的话,所有的问题都只是在能不能得到头一个节点,当前节点的内存空间是已知的。   

面试题14:调整数组顺序使得奇数位于偶数前面

头尾换,很多题都有这种思路。

面试题15:链表中倒数第k个结点

主要是要注意容错

面试题16:反转链表

注意链表不是一成不变的链表,因为链表是可以灵活变换的所以要利用这个特性,只要在变换的时候保存好各种指针就好了。

如果觉得变成树好解决问题的话,比如一个结点想指向两遍,那就断开用三个指针吧,把临时状态保存好。

面试题17:合并两个排序的链表 

在板书解决方案的时候可以考虑在函数开头部分留一些空白,万一要补特殊条件或者入口条件或者容错什么的,可以有地方书写,省得下面擦一大片。 思路考虑清楚后,还是尽量先写容错和特殊情况。

面试题18:判断B是不是A的子树

这个我对robust倒是还考虑了挺多,就是遇到树的时候稍微有点思路不是很清晰,还得多做做二叉树的题。



面试题19:二叉树的镜像

不算太难的吧,就是看到新概念不要慌就好,二叉树递归的还得多练。

面试题20:顺时针打印矩阵

不是所有的矩阵都是方阵(行列相等),在写测试用例的时候要考虑这个。

面试题21:包含min函数的栈

辅助栈  (主要是要考虑动态的情况,尤其是删除).不要吝啬辅助空间。

面试题22:栈的压入弹出序列

说实话刚看到这个题和例子的时候,没太明白题在说什么。 要是面试的时候碰到这种情况估计得死命沟通吧。

面试题23:

从上往下按层打印二叉树

其实就是BFS

面试题24:二叉搜索树的后序遍历序列

注意是二叉搜索树,凡是题目中有任何提示说是已排序的,肯定要利用排序的性质。  呵呵,第一次面试的教训还不够深刻么。,。

所以要用规律来结题啦,,而不是用普通的遍历什么的。

面试题25:二叉树中和为某一值的路径

这道题比CC上那道类似的题要简单,因为这个的路径指的是从根出发的路径,所以只要用栈迭代实现前序遍历就好了。CC上那个题属于动态规划了。

面试题26:复杂链表的复制

这个,呵呵,额,O(n^2)的方法是肯定不会用的啦,,

倒是想到辅助hash表了,不过第三种方法思路就比较高级了,一下子不好想到了。

遇到复杂的问题的时候,不要畏惧写多个函数。虽然算法问题比较苛求代码短,但是当事情比较复杂,分函数反倒可以理清思路,然后体现下设计和扩展什么的。

这个题虽然是复制链表,但是还是大胆的对原链表进行了改动什么的,所以有时候思考问题要大胆一点。

面试题27:二叉搜索树和双向链表 

中序遍历。  有操作的时候不要只想先迭代,其实递归的代码更好写。

当然,链表必备,,注意头指针和尾指针。

这个题还有时间的话也可以练习一下。

面试题28:字符串的排列

这个题也是写过好几遍了,比较经典,可以再写一遍。主要是划分小问题的思路。  还有,error有时候不知道是返回还是抛异常的时候,可以再外面嵌套一个父函数,保证主函数的出口值没有异常。至于父函数怎么处理可以跟面试官讨论。

面试题29:数组中出现次数超过一半的数字

这两种O(n)的解法感觉都挺不错的。

面试题30:最小的k个数

用最大堆的解法应该挺熟悉了,复杂度是nlogk。(这种解法对于大数据来说有节省内存空间的优势。) java里最大堆的语法是

PriorityQueue<Integer> queue =newPriorityQueue<Integer>(10,Collections.reverseOrder());

但是用partition的解法,以及刚才那道题的partition解法可以练习一下。

面试题31:连续子序列的最大值 

这就是那道动态规划曾经让我很伤心的经典例题。

面试题32:从1到n的整数中1出现的次数

十进制数字位数=logn 

我的解法和这里说的想法稍微有点不一样,待验证。

面试题33:把数组排成最小的数

对于排序来说,识别出comparator怎么实现的是很重要的一条。这个题如果要证明这个思路的话,嗯。。

面试题34:丑数

遇到复杂的问题的时候,还是用数学归纳的思想来考虑思路比直接想总结规律要容易些。

面试题35:第一个只出现一次的字符

常规的ASCII hash题了。

面试题36:数组中的逆序对

稍微有点思路,不是太具体。当然O(n^2)的解法就不值一提了。有点归并的意思。所以把快排和归并的代码再写写。 快排注意多变通partition那部分。

面试题37:两个链表的第一个公共节点

这个辅助空间的解法用的是两个栈,然后从结尾同步比较。 其实我觉得可以用个辅助hash表,先把第一条装进hash表里面,然后再依次看第二个节点里面在hash里面有没有值。判断的时间是O(1),总时间还是O(m+n);

不过把链表的长度截成一样的,再同步比较,然后不用辅助空间的思路确实挺好的。

面试题38:数字在排序数组中出现的次数

利用二分查找就要好好用,别把二分也用成了O(n)。

面试题39:二叉树的深度

虽然是道比较简单地题,但是关于树的都还可以再多写写。

PLUS:后序遍历判断是否平衡。  记得平衡树还有好些代码的,可以回去翻翻以前写的。适当的时候记得自底向上。

面试题40:数组中只出现了一次的两个数字

这个:任何数字异或自己都为0.  <- 坑姐啊,你觉得就算姐姐知道这个结论能一下想到么。 当然现在可能是多一条思路了

异或这个思路也就罢了。  根据为1的位数来把数组分成两个小数组,嗯,多学着点。

还有就是这个题结论是要两个数字,但是思路却先从一个数字的例子开始,划分问题就是成功的一半么。

面试题41:和为s的两个数 VS 和为s的连续数列

如果思路是假设数字为正数的话一定要说出来和面试官讨论 。  不然还是假设有正有负吧

连续数列那个优化终止条件还是蛮重要的,时候不用遍历完全就可以终止了。

面试题42:翻转单词顺序 VS 左旋转字符串

关于两次翻转字符串的一些思路。

面试题43:  n个骰子点数    (我才知道搜狗输入骰子是念做tou zi)

面试题44:扑克牌的顺子 

主要是不要忽略个各种建模的可能情况。  还有这个虽然用bucket sort比quicksort要快,但是因为n比较小,所以其实也没太大区别。

面试题45:圆圈中最后剩下的数字 

先总结数学公式再做题好帅的说。

面试题46:求1到n的和,不能用加减乘除,循环,if等

面试题47: 不用加减乘除做加法

面试题48:不能被继承的类

面试题49: 字符串转成整数

与整数相关的要考虑:1:空;2:符号;3. 是否浮点:4.整数位是否溢出; 5.非法输入

面试题50:树中两个节点最低公共祖先 

这个也做过,不过是树的再做一遍。  假设条件不同,解决方案也不一样。 


你可能感兴趣的:(何海涛)