小白一路走来,连续刷题三年,谈谈我的算法学习经验( 三 )


但是,记住,前期你可以多刷这种题练手,提升自己的乐趣,但,我还是建议你慢慢跳出舒适区,去做一些自己不擅长的题,并且找段时间一直刷这种题 。例如,我觉得我在递归方面的题还是挺强的,
但是,我对动态规划的题,很菜,每次都要想好久,每次遇到这种题都有点害怕,没什么信心 。不过有段时间我觉得只刷动态规划的题,直接在 leetcode 选定专题,连续做了七八十道,刚开始很难受,
后来就慢慢知道了套路了,一道题从两三个小时最后缩到半小时,简单的十几分钟就搞定 。感觉自己对这类型的题也不惧怕的 。
所以,建议你,一定要学好跳出自己的舒适区 。
4、推荐一些刷题网站
我一般是在leetcode和牛客网刷题,感觉挺不错,题目难度不是很大 。
在牛客网那里,我主要刷剑指Offer,不过那里也有个在线刷leetcode,不过里面的题量比较少 。牛客网刷题有个非常方便的地方就是有个讨论区,那里会有很多大佬分享他们的解题方法,不用我们去百度找题解 。所以你做完后,实在想不出,可以很方便着去看别人是怎么做的 。
至于leetcode,也是大部分题目官方都有给出答案,也是个不错的刷题网站 。你们可以两个挑选一个,或者两个都刷 。
当然,还有其他刷题的网站,不过,其他网站没刷过,不大清除如何 。
至于leetcode,有中文版和英文版,个人建议英文版,英文版里面有各种大佬的解法分析 。
leetcode有中文版
英文版
根据自己的兴趣选 。
5、学习一些解题技巧
说实话,有些题在你没看别人的解法前,你好不知道有这么美妙优雅的解法,看了之后,卧槽,居然还可以这样 。而我们在刷题的过程中,就要不断累积这些技巧,当你累计多了,你就会形成一种
神经反应,一下子就想到了某种方法 。解题技巧很多,例如数组下标法、位图法、双指针等等,我自己也分享过一篇总结一些算法技巧的文章 。给你举个例子吧,有时候有些技巧真让你大喊“卧槽” 。
1、找出没有重复的数
给你一组整型数据,这些数据中,其中有一个数只出现了一次,其他的数都出现了两次,让你来找出一个数。
这道题可能很多人会用一个哈希表来存储,每次存储的时候,记录 某个数出现的次数,最后再遍历哈希表,看看哪个数只出现了一次 。这种方法的时间复杂度为 O(n),空间复杂度也为 O(n)了 。
然而我想告诉你的是,采用位运算来做,绝对高逼格!
我们刚才说过,两个相同的数异或的结果是 0,一个数和 0 异或的结果是它本身,所以我们把这一组整型全部异或一下,例如这组数据是:1,2,3,4,5,1,2,3,4 。其中 5 只出现了一次,其他都出现了两次,把他们全部异或一下,结果如下:
由于异或支持交换律和结合律,所以:
1^2^3^4^5^1^2^3^4 = (1^1)^(2^2)^(3^3)^(4^4)^5= 0^0^0^0^5 = 5 。
也就是说,那些出现了两次的数异或之后会变成0,那个出现一次的数,和 0 异或之后就等于它本身 。就问这个解法牛不牛逼?所以代码如下
int find(int[] arr){ int tmp = arr[0]; for(int i = 1;i < arr.length; i++){ tmp = tmp ^ arr[i]; } return tmp;}
时间复杂度为 O(n),空间复杂度为 O(1),而且看起来很牛逼 。
2、m的n次方
如果让你求解 2 的 n 次方,并且不能使用系统自带的 pow 函数,你会怎么做呢?这还不简单,连续让 n 个 m 相乘就行了,代码如下:
int pow(int n){ int tmp = 1; for(int i = 1; i <= n; i++) { tmp = tmp * m; } return tmp;}
不过你要是这样做的话,我只能呵呵,时间复杂度为 O(n) 了,怕是小学生都会!如果让你用位运算来做,你会怎么做呢?
我举个例子吧,例如 n = 13,则 n 的二进制表示为 1101, 那么 m 的 13 次方可以拆解为:
m^1101 = m^0001 * m^0100 * m^1000 。
我们可以通过 & 1和 >>1 来逐位读取 1101,为1时将该位代表的乘数累乘到最终结果 。直接看代码吧,反而容易理解:
int pow(int n){ int sum = 1; int tmp = m; while(n != 0){ if(n & 1 == 1){ sum *= tmp; } tmp *= tmp; n = n >> 1; } return sum;}
【小白一路走来,连续刷题三年,谈谈我的算法学习经验】时间复杂度近为 O(logn),而且看起来很牛逼 。