剑指offer新年刷题(JAVA) 持续完善更新

一、序言今天(1月30日)开始春节放假了,一共八天假期,翻出了压箱的《剑指offer》带回了老家过年。一共68题,计划新年每天刷十题,尽量克服走亲戚和个人娱乐等干扰因素,假期结束前争取刷完吧。先写个开头,后续每天持续完善和记录刷题过程和个人题解,贵在坚持。刷的题目自己写的代码实现放在本文最下面的表格中,后续附上自己写的Java题解对应的链接。二、每日学习日志记录(记录刷题过程及思路等)(1)1月30日日记面试题1:赋值运算符函数,C++相关的,略。面试题2:实现Singleton模式,就是手
摘要由CSDN通过智能技术生成

一级目录

二级目录

三级目录

一、序言

今天(1月30日)开始春节放假了,一共八天假期,翻出了压箱的《剑指offer》带回了老家过年。
现在是凌晨一点,顺带写了个新年的学习计划。
一共68题,计划新年每天刷十题,尽量克服走亲戚和个人娱乐等干扰因素,假期结束前争取刷完吧。
先写个开头,后续每天持续完善和记录刷题过程和个人题解,贵在坚持。
刷的题目自己写的代码实现放在本文最下面的表格中,后续附上自己写的Java题解对应的链接。

二、每日学习日志记录(记录刷题过程及思路等)

(1)1月30日日记

写好的内容电脑锁屏没保存,心态蹦了!Ctrl + S的重要性。重来一遍。

面试题1:赋值运算符函数,C++相关的,略。

面试题2:实现Singleton模式,就是手写单例。
单例的话有五种实现:饿汉式,懒汉式线程安全/线程非安全,DCL双检锁,内部类,枚举。
饿汉式、懒汉式、DCL这几种我都可以直接手写出来,很熟悉。

面试题3题一:数组中重复的数字
这道题自己的思路就是直接使用哈希表实现,使用HashSet和其add方法实现,很容易想到。时间复杂度和空间复杂度都是O(n)。
再看看书本上给出的题解:
方法一:先排序数组,再遍历找出重复的数字。排序一个长度为n的数组需要O(nlogn)的时间。
方法二:哈希表。就是我自己想到的题解。
方法三:优化法二空间复杂度到O(1),略

面试题3题二:不修改数组找出重复的数字
方法一:和题一类似,不能修改数组,那就使用哈希表或者使用一个辅助数组。这样的话时间空间复杂度均为O(n)。
方法二:使用二分法,将空间复杂度优化到O(1)。
这个方法和二分查找算法类似,只是多了一步统计区间里数字的数目。时间复杂度为O(nlogn).,空间复杂度O(1),相当于以时间换空间。
但是这种算法不能保证找出所有重复的数字,所以个人觉得使用哈希表是最优解。

面试题4:二维数组中的查找
二维数组很久没使用,都已经忘记了,先复习了一下,再继续看题目。
这道题的思路:从右上角或者左下角的数开始比较,我们选取右上角来分析。
总结一下思路:
首先选取数组中右上角的数字。
如果该数字等于要查找的数字,则查找过程结束;
如果该数字大于要查找到的数字,则剔除这个数字所在的列;
如果该数字小于要查找的数字,则剔除这个数字所在的行。
也就是说,如果要查找的数字不在数组的右上角,则每一次都在数组的查找范围内剔除一行或者一列,这样每一步都可以缩小查找的范围,直到找到药查找的数字,或者查找范围为空。

面试题5(字符串相关):替换空格
一开始自己的思路没问题,但是写出来的代码各种报错,API调用等都有问题。后面改用了StringBuilder,注释掉了原本的错误代码改成了正确的代码,细节注意点还是蛮多的这道题。
方法一:使用上面提到的StringBuilder,配合append方法使用,还要注意将StringBuilder的参数通过**toString()**方法转成toString。
方法二:直接return s.replace(" “,”%20");但是题目本意应该是想让我们实现这个replace方法,这个API记一下就好。
方法三:使用字符数组,但是这个方法的 String newStr = new String(array, 0, size);这个不容易想到

字符串相关的API很多,后续好好总结一下。

面试题6(链表相关):从尾到头打印链表
这道题的话不难,自己就能想到很多方法实现。
方法一:反转单链表,再遍历即可。(迭代+递归反转都写一下)
方法二:栈实现。栈的先进后出满足这道题的需求。这样的话空间复杂度提高了,但是不会修改链表,根据实际需求选择对应的方法,都不难。
方法三:方法二的优化,使用递归实现。
递归本质上就是一个栈结构,所以可以用递归实现,代码更简洁。
但是递归有一个问题,当链表非常长的时候,会导致函数调用层级很深,从而导致函数调用栈溢出,之前遇到过这个即stackoverflow错误。所以本方法不考虑,仅用于总结拓展。

面试题7(树相关):重建二叉树(由前序和中序遍历重建二叉树)
先复习一下树三种遍历的概念
前序遍历:先访问根节点,再左子节点,再右子节点。
中序遍历:先访问左子节点,再根节点,再右子节点。
后序遍历:先方位左子节点,再右子节点,再根节点。
遍历的话有递归和循环两种实现,我个人习惯使用递归,因为代码实现简单,一下子就能写出来。

二叉树有很多特例:
比如二叉搜索树:在二叉搜索树中,左子节点总小于等于根节点,右子节点总大于等于根节点。
二叉树的另外两个特例是堆和红黑树
堆分为最大堆和最小堆
在最大堆中根节点的值最大,在最小堆中根节点的值最小。
红黑树是把树种的节点定义为红、黑两种颜色,并通过规则确保从根节点到叶节点的最长的路径的长度不超过最短路径的两倍。
之前看过的HashMap源码就是基于红黑树实现的。

整理完基本概念,回到我们这道题目本身。

面试题8:二叉树的下一个节点

面试题9题一:用两个栈实现队列
面试题9题二:用两个队列实现一个栈
栈的话就是先进后出,队列的话是先进先出,基于这种差异来实现题目要求。题二这种之前遇到过,一个队列插入另一个队列,剩一个元素的时候交换队列就可以实现两个队列实现一个栈。
题一的话更简单,在stack1中插入元素a,b,c,然后出栈至stack2中,stack中元素即cba,再将stack2依次出栈,得到的就是abc,满足了队列的先进先出顺序。

面试题10题一:斐波那契数列
看题前先总结一下算法和数据操作相关。
很多算法可以基于递归循环来实现,递归的话代码比较简洁,但是性能不如循环实现。
由于递归是函数调用自身,而函数调用有时间和空间的消耗:每调用一次,都需要在内存栈中分配空间以保存参数、返回地址及临时变量,而且往栈里压入数据和弹出数据都需要时间。(所以递归效率不如循环)
并且除了效率外,当递归层数过多时有一个stackoverflower调用栈溢出的报错。前面的分析中已提及每一次函数调用需在内存栈中分配空间,而每个进程的栈的容量是有限的,当递归调用的层级过多时,就会超出栈的容量,从而导致调用栈溢出。

算法相关的题目应该重点掌握二分查找、归并排序和快速排序(几大排序之前都看过了,再复习一下思路手写一下)
总结一些解题技巧:
(1)如果要求在二维数组(可能具体表现为迷宫或者棋盘等)上搜索路径,可以尝试使用回溯法。通常回溯法很适合用递归实现。
如果被限制不可以用递归,就使用栈来模拟递归
(2)如果是求某个问题的最优解,并且该问题可以分为多个子问题,那么可以尝试使用动态规划
在用自上而下的递归思路去分析动态规划问题时,会发现子问题直接存在重叠的更小的子问题。
为了避免不必要的重复计算,我们用自下而上的循环代码来实现,也就是把子问题的最优解先算出来并用数组(一般是一维或者二维数组)保存下来,接下来基于子问题的解计算大问题的解
(3)贪婪算法:如果告诉面试官动态规划的思路之后,面试官还在提醒说在分解子问题的时候是不是存在某个特殊的选择,如果采用这个特殊的选择将一定能得到最优解,那么面试官这样的提示意味着该题可能适用于贪婪算法
(4)位运算
可看成一类特殊的算法,它是把数字表示成二进制后对0和1的操作。
由于位运算的对象为二进制数字,所以不是很直观,但是掌握它也不难。
因为位运算只有与、或、异或、左移、右移5种位运算。

知识点总结完毕,回到我们这道斐波那契数列的题目。
方法一:递归实现(自上而下),但是效率太低了,当n很大时,计算量很大。并且还有很多重复计算,不建议使用。
方法二:优化法一(自下而上),即先根据f0和f1算出f2,再根据f1和f2算出f3。。。以此类推算出第n项。这种思路的时间复杂度是O(n)
方法三:法三:公式法,比较少见,略了。

另外,以下面的爬台阶为例,个人想到了使用常量p,q,r代替数组的方式,可以优化空间复杂度。

面试题10题二:青蛙跳台阶问题
就是斐波那契数列的实际使用,可以用常量代替数组优化一下空间复杂度,这道题蛮简单的,直接写一遍贴代码就可。

面试题10题三:青蛙跳台阶问题拓展,数学归纳法证明是2的n-1次方。

面试题10题四:2X1的矩阵覆盖更大的矩阵有多少种方法:
还是斐波那契数列的使用。

(2)1月31日日记

年三十各种忙活。。。

(3)2月1日日记

年初一同上,比想象中的事情多。。。

(4)2月2日日记

年初二下午,继续开始刷题

查找与排序相关的知识:
查找与排序都是经常使用到的算法。
查找相对简单,就是顺序查找、二分查找、哈希表查找和二叉排序树查找。
题11旋转数组的最小数字和53在排序数组中查找数字都可以用二分查找算法解决。

小提示:如果题目要求在排序的数组(或者部分排序的数组)查找一个数字或者统计某个数字出现的次数,那么我们都可以尝试用二分查找算法

排序比查找复杂一些。几大排序算法掌握即可,手写一下。特点要烂熟于心,记住空间复杂度和平均以及最差时间复杂度,比较优缺点。

面试题11:旋转数组的最小数字(细看,考虑特殊情况要全面)
使用左右指针p,q基于二分法思想,取中间值与p,q比较,移动p,q的位置,时间复杂度O(logn)

面试题12:矩阵中的路径(回溯法)

面试题13:机器人的运动范围(回溯法)

动态规划和贪婪算法
面试题14:剪绳子

位运算
面试题15:二进制中1的个数

(5)2月3日日记

高质量的代码相关总结:
不能出现下面这种错误:

double d1,d2;
if(d1 == d2) //错误写法,由于精度原因,不能用等号判断两个小数是否相等,可参考面试题26树的子结构

命名要规范,最好用完整的英文单词组合命名变量和函数。

考虑代码的完整性,比如面试题17,打印1到最大的n位数,如果n是很大的数字,就不能用int,需要用特殊的数据结构比如字符串或者数组来表示大的数字,确保不会溢出。

还要保证代码的可扩展性和可维护性。参考面试题21调整数组顺序使奇数位于偶数前面。

面试题16:数组的整数次方
要考虑底数是0的情况,如果指数是负数就会报错。以及指数分别为正数,负数,0的情况。
此外可以提高一下效率,公式递归实现看一下。

面试题17:打印从1到最大的n位数
要考虑大数问题的陷阱。

面试题18题一:删除链表的节点
遍历一遍链表进行删除即可实现,但时间是O(n),
而题目要求是O(1)时间实现,细看
面试题18题二:删除链表中重复的节点

面试题19:正则表达式匹配

面试题20:表示数值的字符串

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

代码的鲁棒性(健壮性,即程序能够判断输入是否合乎规则要求,并对不符合要求的输入进行合理的处理):
考虑各种空指针,输入的字符串内容为空等情况。
面试题22中,考虑链表中的节点数目不是大于k个的情况考虑。

面试题22:链表中倒数第K个节点
这题不是很难,能直接手写。
就是考虑一下链表中节点数如果不大于k这种情况即可,注意代码健壮性。
除了遍历实现,还可以用双指针实现。

面试题23:链表中环的入口节点:
方法一:HashSet
方法二:快慢指针实现

面试题24:反转链表
递归和迭代两种方法都写一下,不难,就是注意判空等。

面试题25:合并两个排序的链表
链表题之前看的比较多还是很熟悉的,直接递归实现就可以了。

面试题26:树的子结构(TODO,待看和整理)
树的指针操作比链表复杂一些,后面再看吧。

(6)2月4日日记

(7)2月5日日记

(8)2月6日日记

三、第一遍刷题过程中没有直接写出来需要再次刷的算法题汇总

四、题目及自己写的代码链接列表

序号及题目个人题解链接
2.实现Singleton模式
3.数组中重复的数字
4.二维数组中的查找
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值