- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 566869 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 175284
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
+ e! H0 Y1 d1 C d算法越学越扎心,有没啥破解之法?
9 z) Y& P2 }, |$ l# F) G算法越学越扎心,有没啥破解之法?
* g1 v3 _) [. ]2 r
! v r; ?- A. J" A- u对于算法的学习,我也是从一个小白一步步走来,当然,现在仍然很菜,,,不过,鉴于我觉得还有一些人比我更菜了,我决定谈谈我算法学习过程走过的坑,以及自己总结的一些经验。
9 A9 Z6 G9 k3 e* r
, H- _# Z# I# @/ v) g4 W" o) C切勿盲目刷题:刷题前的知识积累, Z. a9 V- _7 l' P9 B# G
( U' K1 a; g# y% `/ O* y
说实话,想要提高自己的算法,真的没啥捷径,我觉得最好的捷径就是脚踏实地着多动手去刷题,多刷题。' O2 ?. c+ i- x; f9 G
% K/ R4 ]+ v4 R, d, _4 W但是,我必须提醒的是,如果你是小白,也就是说,你连常见的数据结构,如链表、树以及常见的算法思想,如递归、枚举、动态规划这些都没学过,那么,我不建议你盲目疯狂着去刷题的。而是先去找本书先去学习这些必要的知识,然后再去刷题。
! D `7 K; X6 N# g4 o N* ?/ s# x: ]1 L4 c: [2 n0 h _
因为,如果这些基础都不懂的话,估计一道题做了几个小时,然后看答案都看不懂,做题没有任何思路,这是很难受的。久而久之,估计没啥动力了,我刚开始就是这样,一道题答案看一天,然而还是不大懂,什么回溯啊,暴力啊,还不知道是啥意思。
/ G3 L2 v8 }' U8 u, ^8 k- |% l( y# ?; a3 H. t8 {: l
也就是说,假如你要去诸如leetcode这些网站刷题,那么,你要先具备一定的基础,这些基础包括:6 ?/ \; A8 ?" |: j4 f$ P
% h- n! Z- X) Z" R( Y
1、常见数据结构:链表、树(如二叉树)。(是的,链表和二叉树是重点,图这些可以先放着)
, V! g; `* N, @2 N* H, I; _
* r& W0 K) h8 z6 q1 g: i2、常见算法思想:贪婪法、分治法、穷举法、动态规划,回溯法。(贪婪、穷举、分治是基础,动态规划有难度,可以先放着)# i1 M: b# a8 m& ^# N
, \3 H3 q: S7 x6 D& N以上列出来的算是最基本的吧。就是说你刷题之前,要把这些过一遍再去刷题。如果你连这些最基本的都不知道的话,那么你再刷题的过程中,会很难受的,思路也会相对比较少。
" P) U a- q0 F; w8 o7 u9 {. e, |5 }, B6 m3 a$ ^! z' Z
总之,千万不要急,先把这些基本的过一遍,力求理解,再去刷题。& `2 M3 U* I$ L! [$ n& |
* V, K" J! b5 J' h在这里,我推荐基本我大一时看过的书籍吧,感觉还是非常不错的,如果对于数据结构时零基础的话,那么我建议你可以看《数据结构与算法分析:C语言描述版》这本书,这本书自认为真的很 nice,当时我把这本书里面的全部都看了,并且 coding 了一遍,感觉整个人有了质的飞跃。
6 X: F, d a7 b5 Y( ^ U3 o& m C2 m" H" \5 M9 [& t+ \
后面我时在一些学校的OJ刷题,当时看的一本书叫做《挑战程序设计大赛》,日本作家写的,我觉得这本书也很nice,里面有分初级,中级和高级三个模块,基础比较差的可以从初级开始看起。: x0 i# s6 C& r) G% |& ? O3 Y0 P
! L, Q; N! v: ?) c/ e" a当然,这两本书,你可以在这个Github上找到:https://github.com/iamshuaidi/CS-Book
1 e) G8 S l! F/ r总结下:/ W) N& b" X6 ^0 i
J2 I0 |! W0 Z0 b0 i. |$ ^
提高数据结构与算法没啥捷径,最好的捷径就是多刷题。但是,刷题的前提是你要先学会一些基本的数据结构与算法思想。& `* O- c/ }* j. }, f
" u J4 `; m3 H- k) i) X
AC不是目的,我们要追求完美
; m5 s& A, s* T; x6 _4 w) ?3 j( D$ t* B) f
如何刷题?如何对待一道算法题?
8 \0 ?' g! ^$ {" b" {$ P+ d! V! u& ?2 W8 v# e: l# l; E
我觉得,在做题的时候,一定要追求完美,千万不要把一道题做出来之后,提交通过,然后就赶紧下一道。我认为这意义不大,因为一道题的解法太多了,有些解法态粗糙了,我们应该要寻找最优的方法。! F! q6 @, t2 T2 C! t: I
4 I' H- _; p* n# X0 s0 ?
算法能力的提升和做题的数量是有一定的关系,但并不是线性关系。也就是说,在做题的时候,要力求一题多解,如果自己实在想不出来其他办法了,可以去看看别人是怎么做的,千万不要觉得模仿别人的做法是件丢人的事。
/ `. e! A7 q" ^; K8 f1 B# c
3 p; J }8 }1 G我做题的时候,我一看到一道题,可能第一想法就是用很粗糙的方式做,因为很多题采用暴力法都会很容易做,就是时间复杂度很高。之后,我就会慢慢思考,看看有没其他方法来降低时间复杂度或空间复杂度。最后,我会去看一下别人的做法,当然,并不是每道题都会这样执行。
3 X1 _. k& @8 z
/ d- w) K+ y" U# }5 P衡量一道算法题的好坏无非就是时间复杂度和空间复杂度,所以我们要力求完美,就要把这两个降到最低,令他们相辅相成。
% u/ l: d% F7 b* P7 ~5 K6 P0 |. S0 `# G( O& B: w9 l
我举道例题吧:
. @1 T8 Y0 n: Q6 q( p7 u8 {% l, `" }. k! ^/ l
问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?- Y" I( y' \& G, q6 o) D
! B. O' D4 f y) r这道题我在以前的分章分析过,不懂的可以先看下之前写的:递归与动态规划—基础篇17 _! _# [1 w$ u* c2 d- W
9 Q+ W' y! A( w5 `- y6 }
方法1::暴力递归
) H7 {+ F" J* w K. l5 X8 G" Y/ _/ l8 p5 U4 B4 L" i
这道题不难,或许你会采取下面的做法:; ~* y7 O% E# R+ {9 H
4 n' r2 X3 Y% x4 L% S: W+ }! \/ Bpublic int solve(int n){
- ^& ~/ {; p/ [ if(n <= 2){
4 C# C+ R* o! M& s; U return n;& z' J8 n: m5 ] u, Z0 R
}else{
/ r+ Y J& h9 J0 ] return solve(n-1) + solve(n-2);& B9 E* \$ G4 q# Q; C
}
, r8 L% c i P6 N}0 |. d) k& J4 w7 o5 I
1
[: p! S0 R' x' W; Q. }2
0 t; z+ v# L' F& ~3; _( I" O0 q$ z& U% @
43 j- Y7 U" ]9 I, S* a% U3 H
58 F9 K$ T t0 x+ E
64 J) |0 K' l, v3 w
7& o6 I8 Y$ y/ K6 _4 L6 G) q: ]
这种做法的时间复杂度很高,指数级别了。但是如果你提交之后侥幸通过了,然后你就接着下一道题了,那么你就要好好想想了。
' [* S3 h7 p1 [/ }! q e
; G8 H& T9 q, C6 c" X) m h方法二:空间换时间
. e$ D- P* s' t7 o* I2 ]; v3 H! W
0 S8 W/ l8 Q8 c$ o力求完美,我们可以考虑用空间换时间:这道题如何你去仔细想一想,会发现有很多是重复执行了。不行你可以画个图
0 G- f1 p9 k! E1 E
- J. T0 M; N2 N5 p所以可以采取下面的方法:' }% @8 L A" w2 V8 r: G! i
# F" S4 |0 [2 F. S
//用一个HashMap来保存已经计算过的状态9 j% k% w7 g9 r# h' U& Z6 [
static Map<Integer,Integer> map = new HashMap();& C( ]: m- E' a
public static int solve(int n){
! c' R8 ^* P% h if(n <= 2){( Y, ~. z2 A6 _6 u
return n;- A a6 h( d3 @! @9 d* `: q, g) P9 m
}else{//是否计算过% T: {% F) ^: M3 @3 R3 E
if(map.containsKey(n)){ r8 G* V# L7 p1 b0 A
return map.get(n);
8 q$ x! M ?6 O) } J% ~ }else{' n7 Z+ y4 Z$ v
int m = solve(n-1) + solve(n-2);
( |. X a4 c5 ~ map.put(n, m);0 n$ ^) ?- O' ]3 e8 f9 a) a: V ]
return m;
) ?( O. G) w" G! H, t0 f }. H2 }% \, ~+ [! H$ k% z, S
}1 F0 V+ k" @ @& f
}
* r7 m$ i% T# o; N/ Q
8 R* F7 f2 o, t( F6 d12 S/ U( g; o- v& C4 A4 w6 P! Y/ l
2
* \* T& @2 j$ T3' Z$ ]0 @' t$ a
49 D- R. J% F2 O6 f
5
% m% d7 z' _8 i" J; o; e/ H6
, y8 F! g3 F& p7 w+ X0 O7
) q' i$ Y* k7 b5 V; z0 d$ a9 ~8
$ X* h H6 R' L1 c& O) x* H9
5 L5 F% d1 }1 F' {103 O2 N5 [) o' o% s w% q
11
/ A; l4 n7 w6 C3 R3 c$ I" f( y+ B12 d4 [, B; M/ h
13- s' A v9 r$ z" h7 k Y
14' e' I8 _! ]7 h; C; b& X9 ^
15' x" \. n3 `" p% c; R
16
2 ^3 s& [6 x; u5 |* D" G$ p3 N$ n这样,可以大大缩短时间。也就是说,当一道题你做了之后,发现时间复杂度很高,那么可以考虑下,是否有更好的方法,是否可以用空间换时间。2 d4 }- o. s$ u% X
3 i* j, k. e8 l; ^- @ ~方法三:斐波那契数列
! k: ~7 _4 W/ W4 G3 z5 c
+ @7 m, `/ s2 N p+ l" `实际上,我们可以把空间复杂度弄的更小,不需要HashMap来保存状态:
. x D5 i, n% b, H) d7 r
/ G8 Y2 v2 F8 O4 Gpublic static int solve(int n){
3 \7 C7 h$ x7 m6 u3 d4 @7 q, | if(n <= 2){6 \7 r4 H( k3 A) a+ P
return n;
: I6 a; v+ @) w r! z4 K8 b/ d7 X }
9 j/ a* H* r9 l, i& `) ]* T z int f1 = 0;% g! z' p1 d' B1 `3 }& b* ]9 J
int f2 = 1;
: ~$ r/ _7 k+ L int sum = 0;
# K/ t' ~! ~3 H. k! h for(int i = 1; i<= n; i++){& U0 W" B3 v' j4 t
sum = f1 + f2;
! W+ y' A4 C; R" T' v f1 = f2;
- w9 z* W7 r0 h% K3 w f2 = sum;
5 Q" T2 S/ W: e) h- v }; D1 X$ ~& Y) f n, g
return sum;; \+ y" i- t) H
}9 z5 g( P% z( C5 V& l8 {- x5 \
1
8 u* j! G z/ ?% e3 O3 _6 o, `9 o2" B$ E* a6 l4 _1 s- o
3
: \( ^- \3 L. {* H8 }3 e0 U7 a4* _8 ^ M! U6 t1 \% ?! a
53 L5 D& S1 G0 p+ _6 |" k- z+ j6 P
66 ]& w+ k/ H! x" O1 [. W' T
7
$ _) l; d# J& I4 }6 l$ b, t82 @3 i9 \* u& D2 G) w) h- w0 z8 w
9* A" D2 x8 c, X; Q
10
) j9 }/ e, e7 G% I& z; b5 k11' Y* E- M! f& K
128 z- B( l3 g) X8 ` F& O( d9 b4 M
13
& K* p- b \0 P/ D4 y14
' O* C! B \: {, x$ x我弄这道题给你们看,并不是在教你们这道题怎么做,而是有以下目的:8 E8 ?6 x8 _* h) \+ r! d& k: f
; C# l* |0 r: O# v/ f1、在刷题的时候,我们要力求完美。
# }* Y- W; v% Q; u9 f0 i; O$ T, k+ ^8 C1 G: D; u7 ~
2、我想不到这些方法啊,怎么办?那么你就可以去看别人的做法,之后,遇到类似的题,你就会更有思路,更知道往哪个方向想。
1 h! L% L- d0 u9 P% _* d4 o3 Y5 t! N4 D8 B( |; e% W$ j. q |
3、可以从简单暴力入手做一道题,在考虑空间与时间之间的衡量,一点点去优化。9 ]) g. a3 t% @4 o9 V3 ^) y
" c2 C3 Z' ^& }% }8 L, r
挑战自己,跳出舒适区& Y. X, N5 `1 W z3 y5 O
2 w, J* l5 { Q0 e: I* W: S. b
什么叫舒适区?在刷题的时候,可能有一类题是你比较懂的,你每次一看就有思路,然后半个小时就撸好代码,提交代码,然后通过了,然后,哇,又多刷了一道题,心里很舒服。
6 |" e# j" X( C& a" t, L% B
: p% P7 i$ \( G但是,记住,前期你可以多刷这种题练手,提升自己的乐趣,但,我还是建议你慢慢跳出舒适区,去做一些自己不擅长的题,并且找段时间一直刷这种题。例如,我觉得我在递归方面的题还是挺强的,
) s7 ?1 K5 A. [* K" L& V* U但是,我对动态规划的题,很菜,每次都要想好久,每次遇到这种题都有点害怕,没什么信心。不过有段时间我觉得只刷动态规划的题,直接在 leetcode 选定专题,连续做了四五十道,刚开始很难受,后来就慢慢知道了套路了,一道题从两三个小时最后缩到半小时,简单的十几分钟就搞定。感觉自己对这类型的题也不惧怕的。6 v! S2 k" W' _% ^
. y- b# r# |' V9 B当然,对于动态规划的学习,大家也可以看我这篇广受好评的文章:为什么你学不过动态规划?告别动态规划,谈谈我的经验5 u# H" {8 T$ C2 q) ~9 h
& P4 g2 ?8 a* f7 ]所以,建议你,一定要学好跳出自己的舒适区。
+ T8 s7 {/ e: j' L
- {& m- l" ^1 L* Q u# Y! ~- o5 z一定要学会分类总结- p! G: [: T! w: C6 q; U, k# ]
8 j, l5 y" H, b) Y ]有些人以为 leetcode 的题刷的越多,就一定能越厉害,其实不然,leetcode 虽然有 1000 多道题,但题型就那么几类,我们前期在刷的时候,我是建议按照题型分类刷题的,例如我这整理刷二叉树相关,然后刷链表相关,然后二分法,然后递归等等,每刷一种题型,都要研究他们的套路,如果你愿意去总结,那么 leetcode 的题,其实你刷几百道,有目的、挑选的刷,我觉得就差不多了。
+ L9 c. A! y7 j3 a7 S; b
. _) \0 S" z# T2 P我看过一本书,叫做《程序员代码面试指南:IT 名企算法与数据结构题目最优解》,这本书就非常不错,里面按照栈,队列,链表,二叉树,字符串等一个专题一个专题来刷的,并且每道题都给出了最优解,而且里面的题有一定的难度,感兴趣的,真心不错,如果你把这本书的题全部搞定,并且总结相关套路,那么你的算法一定有很大的提升。2 z6 w4 `% C) ~3 h3 c, K; Y
6 e ]5 f1 f- ]4 V& w4 I推荐一些刷题网站* P8 L J$ P3 X
1 L6 N# R1 Y) z0 c4 d: o
我一般是在leetcode和牛客网刷题,感觉挺不错,题目难度不是很大。! G7 V6 J2 @& |/ Y& @+ C
& [ M& g) \% V在牛客网那里,我主要刷剑指Offer,不过那里也有个在线刷leetcode,不过里面的题量比较少。牛客网刷题有个非常方便的地方就是有个讨论区,那里会有很多大佬分享他们的解题方法,不用我们去百度找题解。所以你做完后,实在想不出,可以很方便着去看别人是怎么做的。/ V N: ^ m7 N% a2 Z4 m" {; ]
4 q/ G/ v5 {7 y
至于leetcode,也是大部分题目官方都有给出答案,也是个不错的刷题网站。你们可以两个挑选一个,或者两个都刷。
1 i. n' p- b0 V
7 z3 l$ c) E9 V- b- ~+ o4 u4 |当然,还有其他刷题的网站,不过,其他网站没刷过,不大清除如何。6 [9 y1 E1 K* n; n& g/ g* L* p
) P: @9 H4 a! t# p" s5 Y
至于leetcode,有中文版和英文版
! X% w8 @3 \$ B
- D3 b( R0 \! Q7 V3 D/ zleetcode有中文版0 T$ \2 {: D& O# m7 H$ s3 O
6 B3 C% b1 A# \/ Y) z* G
英文版' ?4 b- }# {# F7 k D' k& T' n
' o6 ^/ p0 o3 `, E% R) J
根据自己的兴趣选。' d; q, {( x7 u) P B0 p
0 B. ?, P* e# S0 ]* ^' B u学习一些解题技巧
' ^+ G; e' G* _3 q& Q. M; n% S: B6 ~6 F
说实话,有些题在你没看别人的解法前,你好不知道有这么美妙优雅的解法,看了之后,卧槽,居然还可以这样。而我们在刷题的过程中,就要不断累积这些技巧,当你累计多了,你就会形成一种
/ o U: w2 `/ f* k$ Y" g神经反应,一下子就想到了某种方法。解题技巧很多,例如数组下标法、位图法、双指针等等,我自己也分享过一篇总结一些算法技巧的文章1 e0 G, i8 A9 V2 v! T2 J9 b
& P* u* a" @+ o) w6 Y {/ b
推荐阅读:一些常用的算法技巧总结
M) b3 T+ s- F: v, ?& o& S& t( _: b+ N( z4 f3 t# n7 F
例如在刷题的时候,我们要学会巧用双指针、数组下标法、位运算等等技巧来解决问题,可能会有意想不到的效果。我给你再找点我之前写文章的一些例子吧:9 i3 y, ?* X7 H* ]8 H9 p5 Z
+ F7 i7 H7 F9 D( L4 n
分享一道解法巧妙的算法题) D0 Y- |9 x/ p$ C+ p! O
: D7 N2 O* F' J- L3 \ U7 E$ J【算法技巧】位运算装逼指南
8 q3 n( q$ B7 `1 G v, ?8 C% }, Z9 Q$ K% M( C# n$ L. |
这是个长期累积的过程,我自己也精彩在我的公众号里分享一些解题的文章,感兴趣的可以关注我的公众号:帅地玩编程。. p4 d0 o/ Y/ T5 q" K" [% N
3 E1 v$ ^0 V; n3 e; I$ }$ O再说数据结构发重要性
' Z% T( q5 H) o9 ~# g& f' T4 M6 _, }2 {# X; z, v& x! G! U) B
前面我主要是说了我平时都是怎么学习算法的。在数据结构方法,我只是列举了你们一定要学习链表和树(二叉堆),但这是最基本的,刷题之前要掌握的,对于数据结构,我列举下一些比较重要的:9 k& C$ |$ Y$ q0 m" Q; m1 Y9 V- i
) a4 x5 p; H9 C/ K
1、链表(如单向链表、双向链表)。
; O4 J) @) X) ]6 k1 A& H0 n Q' J, u. r/ w* T$ |7 V* e
2、树(如二叉树、平衡树、红黑树)。9 [. q1 j& C* X0 Z- w
, p1 b4 ~9 |8 \" f% G" y' o) u7 d
3、图(如最短路径的几种算法)。! Z I- }- Y E3 o4 X0 Z
; ^1 h" r1 u Q9 C: W
4、队列、栈、矩阵。
/ q8 I4 Y, a% G$ ^ O+ l* j
- ^: a7 O8 ]7 E* n1 u5 N) |! n* I对于这些,自己一定要动手实现一遍。你可以看书,也可以看视频,新手可以先看视频,不过前期可以看视频,之后我建议是一定要看书。* o: g' X2 T9 D$ H/ D
9 U2 B w, l* ~: H
例如对于平衡树,可能你跟着书本的代码实现之后,过阵子你就忘记,不过这不要紧,虽然你忘记了,但是如果你之前用代码实现过,理解过,那么当你再次看到的时候,会很快就记起来,很快就知道思路,而且你的抽象能力等等会在不知不觉中提升起来。之后再学习红黑树啊,什么数据结构啊,都会学的很快。- R3 @% |7 ~- ]# e4 W0 p# S
5 Z& d0 a- _: ~$ q- e( U2 t对于有哪些值得学习的算法,我之前也总结过,这里推荐给大家程序员必须掌握的核心算法有哪些?,这篇文章居然 40多万阅读量了,有点受宠若惊。, p) z* N' j/ e. R
6 h$ P+ y% |: O7 J. x最最重要# T& {" ~5 z/ u0 l* ]. _! z7 a8 R
$ W- C+ t- F w1 [) [9 R$ v动手去做,动手去做,动手去做。重要的话说三遍。* K$ q& W/ E" r
# b4 K1 @6 h1 |3 Q. P
千万不要找了一堆资源,订好了学习计划,我要留到某某天就来去做…& D2 t O4 Z4 g& I* g( P0 W* b
4 _/ W( z5 v5 f
千万不要这样,而是当你激情来的时候,就马上去干,千万不要留到某个放假日啊什么鬼了,很多这种想法的人,最后会啥也没做的。2 m" I# F# c8 C8 D0 g0 q
: g$ F1 N" }. v5 E1 |4 I也不要觉得要学习的有好多啊,不知道从哪学习起。我上面说了,可以先学习最基本的,然后刷题,刷题是一个需要长期坚持的事情,一年,两年。在刷题的过程中,可以穿插和学习其他数据结构。
/ i ?. ?4 ?+ e' \9 e0 L
: @ e- P7 u! y& p总结一下吧
1 M8 o3 \6 s1 u3 {- i8 E# q7 v" b4 N E, d% k8 F7 W. x$ d
所以我给大家的建议就是,先学习基本的数据结构以及算法思想,不要盲目刷题,接着刷题的过程中,不能得过且过,尽量追求最优解,还有就是要跳出舒适区,逼自己成长,刷题的过程中,要学会分类总结。
1 @3 S) C' @( w0 S
! Z, Y* R# ?, |6 w当然,最重要的,就是你去动手了,不然,一切免谈!
4 x2 M4 Q9 ]% Y* T2 u6 \ X( ^- T
* r' Y) `6 j, k; b( }看在熬夜写过的份上,送我个赞呗,嘻嘻。% u8 E7 b' V7 z4 X8 s
————————————————
0 h4 @9 d* n4 B, R5 y* {+ R$ j版权声明:本文为CSDN博主「帅地」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
7 I( N) i$ l$ r7 R4 P7 u原文链接:https://blog.csdn.net/m0_37907797/article/details/104765116
9 G( ^* X I$ b" N5 Y; \% n4 ~ d6 y1 _! r: ]/ }
! y: }# q$ U# G j; _ C7 n8 } |
zan
|