- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 563411 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174246
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
# R, l8 g5 B; O! u2 N7 \
算法越学越扎心,有没啥破解之法?$ C, f- l8 T1 {! ~1 {( S
算法越学越扎心,有没啥破解之法?
- i7 s0 W" w+ s2 s, O! ^
' F: ]. K, V) A对于算法的学习,我也是从一个小白一步步走来,当然,现在仍然很菜,,,不过,鉴于我觉得还有一些人比我更菜了,我决定谈谈我算法学习过程走过的坑,以及自己总结的一些经验。
; w8 e! e w' }4 G
% a- Q7 Y" o3 f5 l! ~& r; ? g切勿盲目刷题:刷题前的知识积累
0 `. j: ~2 F. l
; u9 m7 \. C; j! |说实话,想要提高自己的算法,真的没啥捷径,我觉得最好的捷径就是脚踏实地着多动手去刷题,多刷题。6 c. g `. F0 @
! a6 M' @0 L f2 \ `8 e' E
但是,我必须提醒的是,如果你是小白,也就是说,你连常见的数据结构,如链表、树以及常见的算法思想,如递归、枚举、动态规划这些都没学过,那么,我不建议你盲目疯狂着去刷题的。而是先去找本书先去学习这些必要的知识,然后再去刷题。% z- d" }; P2 ? a" H; N
+ u& \1 s+ r6 ~% i4 u5 s1 I( ^因为,如果这些基础都不懂的话,估计一道题做了几个小时,然后看答案都看不懂,做题没有任何思路,这是很难受的。久而久之,估计没啥动力了,我刚开始就是这样,一道题答案看一天,然而还是不大懂,什么回溯啊,暴力啊,还不知道是啥意思。6 S8 L" s& N8 I6 Y% m1 w
6 Q0 k% B9 w& N9 I
也就是说,假如你要去诸如leetcode这些网站刷题,那么,你要先具备一定的基础,这些基础包括:
) Y5 W% N0 G$ @6 Y# U
. U- L8 k8 Y/ ]1、常见数据结构:链表、树(如二叉树)。(是的,链表和二叉树是重点,图这些可以先放着)! W( f$ R% p8 L. @4 o8 q* v0 H6 [; N
$ i" M6 ]* s4 @
2、常见算法思想:贪婪法、分治法、穷举法、动态规划,回溯法。(贪婪、穷举、分治是基础,动态规划有难度,可以先放着)3 t' t+ ]3 o0 [0 _/ {
7 j! v. z8 e7 n' ?9 z: l以上列出来的算是最基本的吧。就是说你刷题之前,要把这些过一遍再去刷题。如果你连这些最基本的都不知道的话,那么你再刷题的过程中,会很难受的,思路也会相对比较少。; y4 f9 P3 M; F _- H* B
* @7 C/ t; {$ V F: B3 C总之,千万不要急,先把这些基本的过一遍,力求理解,再去刷题。
2 N+ D" A+ B# E* s9 s0 s7 o
% \: U( ]1 ]$ z$ V) `) h4 z在这里,我推荐基本我大一时看过的书籍吧,感觉还是非常不错的,如果对于数据结构时零基础的话,那么我建议你可以看《数据结构与算法分析:C语言描述版》这本书,这本书自认为真的很 nice,当时我把这本书里面的全部都看了,并且 coding 了一遍,感觉整个人有了质的飞跃。
# f L, A, y/ R1 M# D8 e% o: S4 O, G4 J- V: Z/ W: s) P; z! I' M
后面我时在一些学校的OJ刷题,当时看的一本书叫做《挑战程序设计大赛》,日本作家写的,我觉得这本书也很nice,里面有分初级,中级和高级三个模块,基础比较差的可以从初级开始看起。7 b1 _ y: A0 H
7 L* i8 H$ ~7 Y& \( s$ E当然,这两本书,你可以在这个Github上找到:https://github.com/iamshuaidi/CS-Book5 t1 `1 d8 a, T9 _4 t4 X0 K( w
总结下:! j% o4 z0 a# K" d
; a! F# K" R/ W+ |
提高数据结构与算法没啥捷径,最好的捷径就是多刷题。但是,刷题的前提是你要先学会一些基本的数据结构与算法思想。
( G$ X8 P' K a- B/ t1 q4 V' k# N" d. X& h
AC不是目的,我们要追求完美, h! C9 Y5 d/ @0 ]0 Q5 c' s
I% m6 g1 r+ A( s3 Z/ l' p; F如何刷题?如何对待一道算法题?" U% W6 I! {& |$ W
" B' n. H5 |2 D; m8 E
我觉得,在做题的时候,一定要追求完美,千万不要把一道题做出来之后,提交通过,然后就赶紧下一道。我认为这意义不大,因为一道题的解法太多了,有些解法态粗糙了,我们应该要寻找最优的方法。
5 V. x4 a3 B/ [ U6 y2 y, g
+ ]. f) Z2 A4 ~% B' Z算法能力的提升和做题的数量是有一定的关系,但并不是线性关系。也就是说,在做题的时候,要力求一题多解,如果自己实在想不出来其他办法了,可以去看看别人是怎么做的,千万不要觉得模仿别人的做法是件丢人的事。
; t2 t/ _( n% A/ W. m9 W. J' u8 W' X, v- o
我做题的时候,我一看到一道题,可能第一想法就是用很粗糙的方式做,因为很多题采用暴力法都会很容易做,就是时间复杂度很高。之后,我就会慢慢思考,看看有没其他方法来降低时间复杂度或空间复杂度。最后,我会去看一下别人的做法,当然,并不是每道题都会这样执行。
% E. Q# y/ s3 Y5 u! a( d2 L' {. k8 |' V; ^8 g0 X# ?9 R
衡量一道算法题的好坏无非就是时间复杂度和空间复杂度,所以我们要力求完美,就要把这两个降到最低,令他们相辅相成。
]$ R4 M0 H; D0 E% M( w$ ]6 { A6 U- c$ w& Q% |1 P
我举道例题吧:6 |' e# z8 I1 r7 h
2 K! Z9 o+ `3 }- ?% ?问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?- u1 J& M) i1 P3 ^
4 |& }" g+ R" A" A
这道题我在以前的分章分析过,不懂的可以先看下之前写的:递归与动态规划—基础篇10 f$ V1 a- `2 b& {2 K
# j. B! o# m! Z1 X7 i$ R方法1::暴力递归" u3 p0 C: h' T8 E) z5 e
3 m0 B+ ^& v0 ~( j: U
这道题不难,或许你会采取下面的做法:
2 u7 i9 H# F0 ^3 {; x
( f+ F( E m5 Y, l) j! o j* Mpublic int solve(int n){
0 F* b" v6 \2 ~+ ? if(n <= 2){
- j3 y# q2 B) v return n;
1 U! {1 B( V9 B$ ^' h+ i5 O4 m }else{- G3 |" s( c# { c( {- s" @, \
return solve(n-1) + solve(n-2);
' J$ E( k% H* c! `0 \( F# @ }
1 ^1 |) P3 V/ {5 j}3 n X2 |, E6 b! r
1. l' }7 ~) q* D) B# N6 P) }
28 V0 l2 }( M7 z4 p; d
3
z% |5 R: a( U0 `7 k2 u$ {% p3 b9 C4; R- |5 m8 E9 Z! b
59 F& Y/ }7 t' s
6
0 D( m# c! ?4 a/ X0 R+ J) k7
% R& t) g& r9 ]) }9 `! h3 x( t0 }3 \这种做法的时间复杂度很高,指数级别了。但是如果你提交之后侥幸通过了,然后你就接着下一道题了,那么你就要好好想想了。
+ A1 z: R/ w( u( v& A% h8 b! g
0 F# `: d9 R- H9 R4 }方法二:空间换时间/ ^5 T! S( F# y' G; H2 B) i: `! N5 R
4 Q( W9 P6 w1 Q; l+ \: D1 ` ?
力求完美,我们可以考虑用空间换时间:这道题如何你去仔细想一想,会发现有很多是重复执行了。不行你可以画个图
% t2 a! ?, \5 {( [) }0 S
: S& [% L2 F/ y, |; C所以可以采取下面的方法:$ }: h# D) L0 ] G: m8 u- ^* j
; L' J& L# R% p" I7 X% W; p
//用一个HashMap来保存已经计算过的状态
; u. @% Y8 i2 i) z9 `2 J% m! cstatic Map<Integer,Integer> map = new HashMap();
7 K5 R; F& |/ c0 D5 I' D$ ^public static int solve(int n){
. S2 X3 m. J4 N, z, s0 ]# f1 R if(n <= 2){. v( \3 q7 E2 \1 z$ i
return n;
5 D; |9 z+ \& M, ^ }else{//是否计算过: O) I7 _ N' ?$ C3 W& M# v
if(map.containsKey(n)){
' x/ I0 S) a) [" q! \5 M. w8 g1 W# z return map.get(n);8 k, K# d% Q1 C
}else{# c1 ^3 X5 l8 j0 C7 U; t
int m = solve(n-1) + solve(n-2);
) U; C$ p$ }8 Q9 t8 f! r map.put(n, m);
7 B8 S: \3 d: W3 S1 ? return m;+ }$ L1 }' p! j! ]( s5 K+ i
}2 Y+ |! a6 h8 }2 T
}/ r i* Z9 C2 i' [2 C
}
) k! `2 L: O4 X) _+ L/ U3 A- p9 {& m8 }
1
0 \9 P' X. d0 x2: {$ @ c, `( z9 U h+ g5 Y
31 P; G) }0 h- K- M% I9 e$ _
4
! e! f6 N+ X9 p& e( Q5
+ M4 [% C5 s# R( j; F7 Z8 t6; D/ Y' w4 {' p& S! L5 \# g& X: O
7
: p2 |8 ?: {% r' C5 C4 F: Y8 |0 q( ?/ ^6 J# K& P2 `
9
" }4 y' s, a" V& k10
" Y/ g u# `. z# e; b1 g) N11
. N9 u4 [5 G8 h) M" S12+ d, n/ Z( a, T; l
13
" F/ J; U4 t( n9 c3 {/ N+ p143 z6 {0 ?; d- ~5 x) [
15
& z5 E' Y+ ~' M/ G167 M- B- M0 k& R4 T/ J
这样,可以大大缩短时间。也就是说,当一道题你做了之后,发现时间复杂度很高,那么可以考虑下,是否有更好的方法,是否可以用空间换时间。
+ v3 L" \+ V$ f% f8 y5 N# V. |
' V, ^/ l* G* F. {" c- T方法三:斐波那契数列
# ? [7 u" ~9 Q: ]9 M- y+ S
5 l7 R& H. R& U1 P* f( e实际上,我们可以把空间复杂度弄的更小,不需要HashMap来保存状态:$ R' ]: V/ m s3 _
' x, s+ V4 f7 K9 r: @1 ipublic static int solve(int n){ P' g% i$ R8 K+ ^2 |# p v$ G5 A
if(n <= 2){
" y# r# J( S/ y7 d; m return n;! @: P# `( T7 H- m. h0 h9 X
}
$ H6 l0 v% q6 }$ H" O& Y" @1 ~ int f1 = 0;
# y- A8 j& L4 t2 K7 E( I' g/ Y! u int f2 = 1;
! {- v. @7 K# V' D int sum = 0;
; I0 d' s8 Y4 ~3 {2 Y. z for(int i = 1; i<= n; i++){7 @' ]- Z( k- K, R: m/ J6 i
sum = f1 + f2;4 ~' y- e7 ^9 \( D" q6 }# y6 n+ b1 m
f1 = f2;9 M: ^8 X' q* z8 T
f2 = sum;
2 B! v6 y6 D$ `) \' ` }
' `! X+ r7 u4 N/ Y$ ? return sum;
# M2 k4 u* n* k' Z$ |; K7 \}+ H5 c t' y7 [. `* [" k# L1 D
1$ K/ N6 T' R2 X" O
25 y- s: C4 u9 b+ j6 r
3
% t M% D* g% c, c1 C; N; O4$ |& B! N. t! F* I. }- ?, O
5
, E$ ^# D& y& S8 f1 n6
; D3 I! a2 `% J9 a" H8 {! k3 t7
# @0 K6 A7 i# E M83 B! o" A5 x1 l. ?1 P# Y I. \
9
8 n# @1 j7 c o/ E$ X10
8 i+ M: |6 ]5 M3 {7 w6 d$ T i11
; J# s- K( {' H! P! O; g# [+ `123 k; L1 L0 _5 q
13
+ A P+ r5 @& ?* Y14! @4 j# L0 m! |
我弄这道题给你们看,并不是在教你们这道题怎么做,而是有以下目的:
* m1 A! E$ h5 U4 H& D# u3 c2 O
0 V8 G, L% Y, J5 g1 t1、在刷题的时候,我们要力求完美。
+ v0 s- k4 G! l5 E/ z2 w/ G [: E3 c9 m
6 x) L- Y8 |/ Z1 q; r; c2、我想不到这些方法啊,怎么办?那么你就可以去看别人的做法,之后,遇到类似的题,你就会更有思路,更知道往哪个方向想。, \3 h" z5 H5 q# G
% l2 O. G, i$ a; a8 Q9 a
3、可以从简单暴力入手做一道题,在考虑空间与时间之间的衡量,一点点去优化。- D: o6 I ?7 m3 E
8 Z5 v- e5 S5 ~0 Z a1 U
挑战自己,跳出舒适区" w0 q$ D% }5 g% K! _
5 c7 S) [: Z, Q5 r
什么叫舒适区?在刷题的时候,可能有一类题是你比较懂的,你每次一看就有思路,然后半个小时就撸好代码,提交代码,然后通过了,然后,哇,又多刷了一道题,心里很舒服。
7 i' ?4 \6 q" ~5 ~8 H' U! G8 X/ H' C! o q
但是,记住,前期你可以多刷这种题练手,提升自己的乐趣,但,我还是建议你慢慢跳出舒适区,去做一些自己不擅长的题,并且找段时间一直刷这种题。例如,我觉得我在递归方面的题还是挺强的,) ~& @8 q: V8 ^0 R5 T4 F, q8 U
但是,我对动态规划的题,很菜,每次都要想好久,每次遇到这种题都有点害怕,没什么信心。不过有段时间我觉得只刷动态规划的题,直接在 leetcode 选定专题,连续做了四五十道,刚开始很难受,后来就慢慢知道了套路了,一道题从两三个小时最后缩到半小时,简单的十几分钟就搞定。感觉自己对这类型的题也不惧怕的。
2 S9 ?2 e+ U( D
) Z' k* e( N# Y# s& x当然,对于动态规划的学习,大家也可以看我这篇广受好评的文章:为什么你学不过动态规划?告别动态规划,谈谈我的经验
8 C5 a5 T3 x* H x1 W( D5 ^8 }( g f
所以,建议你,一定要学好跳出自己的舒适区。/ W& ~# H' ^5 y* G7 x* b
+ Z, |& ?* P3 ?- y6 `& a( P& _
一定要学会分类总结
" o, w4 d5 o) e8 Y: q; F
: e6 a! Q; g1 K" j有些人以为 leetcode 的题刷的越多,就一定能越厉害,其实不然,leetcode 虽然有 1000 多道题,但题型就那么几类,我们前期在刷的时候,我是建议按照题型分类刷题的,例如我这整理刷二叉树相关,然后刷链表相关,然后二分法,然后递归等等,每刷一种题型,都要研究他们的套路,如果你愿意去总结,那么 leetcode 的题,其实你刷几百道,有目的、挑选的刷,我觉得就差不多了。7 j) }' w n0 g1 f9 j9 E# w* O
9 K& u( [1 B# A8 M! G8 i X; w
我看过一本书,叫做《程序员代码面试指南:IT 名企算法与数据结构题目最优解》,这本书就非常不错,里面按照栈,队列,链表,二叉树,字符串等一个专题一个专题来刷的,并且每道题都给出了最优解,而且里面的题有一定的难度,感兴趣的,真心不错,如果你把这本书的题全部搞定,并且总结相关套路,那么你的算法一定有很大的提升。: G' `' U' `( {4 h9 I6 y$ w# B
% Q& M& M0 s2 [' n9 A: K0 A推荐一些刷题网站4 N K f) s) o4 }1 H* m* g( s
+ l0 }$ a) B4 B% a我一般是在leetcode和牛客网刷题,感觉挺不错,题目难度不是很大。
6 C( |; ^. I7 k0 {0 I! z' j8 W C" p, A
在牛客网那里,我主要刷剑指Offer,不过那里也有个在线刷leetcode,不过里面的题量比较少。牛客网刷题有个非常方便的地方就是有个讨论区,那里会有很多大佬分享他们的解题方法,不用我们去百度找题解。所以你做完后,实在想不出,可以很方便着去看别人是怎么做的。
; h/ D6 F7 D$ G2 [
) U0 A4 h$ g7 F# I& V) J& W至于leetcode,也是大部分题目官方都有给出答案,也是个不错的刷题网站。你们可以两个挑选一个,或者两个都刷。
; Z/ h; B1 ^2 p
8 X/ B6 r; }7 |# U当然,还有其他刷题的网站,不过,其他网站没刷过,不大清除如何。
* ?! K) x6 j" ~# C) K
; g# l" Z4 A2 H0 Q" l至于leetcode,有中文版和英文版8 F6 w; d# p9 U( }) z' s
* ]9 F0 \' Q' O' N; G9 T% }* kleetcode有中文版( c2 M! B" C4 ?3 s% U& o! W
6 ?$ O- d' c, {1 R英文版) M: e% a7 j1 z0 |
8 d' Y2 R @ J1 \0 a; V* M
根据自己的兴趣选。9 M) k! v$ B. _: z, |: X0 h
* O S! \$ F, y% P" p$ r& _
学习一些解题技巧
) ~& |# E6 K' Y$ y" O( w1 M; w; m9 w- o, r, A7 j
说实话,有些题在你没看别人的解法前,你好不知道有这么美妙优雅的解法,看了之后,卧槽,居然还可以这样。而我们在刷题的过程中,就要不断累积这些技巧,当你累计多了,你就会形成一种# n( K3 f/ Y2 T( S
神经反应,一下子就想到了某种方法。解题技巧很多,例如数组下标法、位图法、双指针等等,我自己也分享过一篇总结一些算法技巧的文章
`" [4 A9 O+ _% w9 ]4 h; q1 k2 T9 l5 q2 C* ]" v% d/ w0 b y2 h
推荐阅读:一些常用的算法技巧总结) H5 n4 ^$ C: ^8 w3 b
+ Y7 T9 a/ ?) q/ `例如在刷题的时候,我们要学会巧用双指针、数组下标法、位运算等等技巧来解决问题,可能会有意想不到的效果。我给你再找点我之前写文章的一些例子吧:5 [) u# X0 ?0 `( M* t" h
) l% h* Y% L- U# q/ J5 T
分享一道解法巧妙的算法题
( t6 z( Y9 t, z' q, R* O
" e" L4 C2 a% T* |" H8 a【算法技巧】位运算装逼指南+ O. F# v! X* ?) u
' ~1 v# \) P- \7 ^$ B1 f
这是个长期累积的过程,我自己也精彩在我的公众号里分享一些解题的文章,感兴趣的可以关注我的公众号:帅地玩编程。7 V: A( |* Z' N
: U9 p$ S) R* C8 ? H
再说数据结构发重要性
, x& ~* q* G) l+ F! }, A7 h+ e3 H4 v( r9 [7 B7 i+ p) ^' J( A
前面我主要是说了我平时都是怎么学习算法的。在数据结构方法,我只是列举了你们一定要学习链表和树(二叉堆),但这是最基本的,刷题之前要掌握的,对于数据结构,我列举下一些比较重要的:- h! v3 Z1 d( f
3 H, J& [& g* Z+ B* x
1、链表(如单向链表、双向链表)。0 {) M- I" z3 I- F+ ?+ Z
4 w# T e2 X0 p, s1 ~; z3 V! o2、树(如二叉树、平衡树、红黑树)。
' K# F. u# K! U' T( `" D- _' S! N7 T0 z* Y% Q- ]
3、图(如最短路径的几种算法)。( S7 O6 N0 N# ~: _0 A
1 q, p, V$ s' q& Y% Y7 v5 i
4、队列、栈、矩阵。. N; N. G5 | ]% m: O' x M" \- A
& [, V$ \$ n% O( Y6 R2 I
对于这些,自己一定要动手实现一遍。你可以看书,也可以看视频,新手可以先看视频,不过前期可以看视频,之后我建议是一定要看书。
% j: K% j2 ]2 X, P# u6 P. s6 |1 S; }/ E* j$ I( T' z
例如对于平衡树,可能你跟着书本的代码实现之后,过阵子你就忘记,不过这不要紧,虽然你忘记了,但是如果你之前用代码实现过,理解过,那么当你再次看到的时候,会很快就记起来,很快就知道思路,而且你的抽象能力等等会在不知不觉中提升起来。之后再学习红黑树啊,什么数据结构啊,都会学的很快。1 C( k% `# r7 r; c h% x
! i4 l" p2 E" z& j% o' V$ \对于有哪些值得学习的算法,我之前也总结过,这里推荐给大家程序员必须掌握的核心算法有哪些?,这篇文章居然 40多万阅读量了,有点受宠若惊。
3 S! e7 a, n+ C% d, F$ q3 h* m3 t0 Q
最最重要+ ^6 R8 k# I% |8 h6 v! b. o
7 n2 r" u/ D+ b- H' u动手去做,动手去做,动手去做。重要的话说三遍。& W. O1 @* z2 d$ ~" y
$ U* R* w3 ^1 P6 O% z0 o千万不要找了一堆资源,订好了学习计划,我要留到某某天就来去做…/ H" }% w$ W |2 C
Y: K; s: n2 l( g u1 K千万不要这样,而是当你激情来的时候,就马上去干,千万不要留到某个放假日啊什么鬼了,很多这种想法的人,最后会啥也没做的。
, k* t' u7 E M
: |4 q+ U8 m0 o% _0 q: w+ k5 y+ B# {2 M也不要觉得要学习的有好多啊,不知道从哪学习起。我上面说了,可以先学习最基本的,然后刷题,刷题是一个需要长期坚持的事情,一年,两年。在刷题的过程中,可以穿插和学习其他数据结构。1 C3 z( h: D% {% f$ o* o2 e& y
0 U: |8 v" \; W2 n2 i总结一下吧 B, a+ T% O9 d$ d1 h
, [6 w+ i% Z" `$ B/ D4 W所以我给大家的建议就是,先学习基本的数据结构以及算法思想,不要盲目刷题,接着刷题的过程中,不能得过且过,尽量追求最优解,还有就是要跳出舒适区,逼自己成长,刷题的过程中,要学会分类总结。
+ g) G3 @1 J4 B& V, {& W
( P, F6 Q* o% k' o$ G1 ]* S当然,最重要的,就是你去动手了,不然,一切免谈!
8 P' ]3 ?, s, W$ d# T& l, P0 M+ A5 v6 J+ y& h7 i
看在熬夜写过的份上,送我个赞呗,嘻嘻。
1 {/ Z5 Y% H+ ~0 D————————————————
4 p6 Z- v" Q/ ^ V( M& E版权声明:本文为CSDN博主「帅地」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。, K; Z- }% s! W# C) ]! D
原文链接:https://blog.csdn.net/m0_37907797/article/details/104765116
! q3 y7 I) D4 G" E: L. I7 n% U3 N) S8 Q2 V5 U2 R) H
% b6 P; s% y: \& v3 u1 v |
zan
|