- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 564648 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174617
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
' V5 W/ U: j3 o4 l6 f8 J3 \
算法越学越扎心,有没啥破解之法?; Q: B0 @. Z9 g) M
算法越学越扎心,有没啥破解之法?% [+ M6 U' K9 z7 S
) b% l8 L3 M2 X7 G' V: q对于算法的学习,我也是从一个小白一步步走来,当然,现在仍然很菜,,,不过,鉴于我觉得还有一些人比我更菜了,我决定谈谈我算法学习过程走过的坑,以及自己总结的一些经验。4 X* N. c# p4 i N/ e4 |7 S6 p5 k
- c" L: `+ R, i% g% K- t) |) ~' a' T
切勿盲目刷题:刷题前的知识积累
* N' B: e7 \* s+ u& o" M( {. C4 d% g3 ?+ r- r0 b
说实话,想要提高自己的算法,真的没啥捷径,我觉得最好的捷径就是脚踏实地着多动手去刷题,多刷题。
1 Q" m& d3 }1 r) Z- b7 G. }& h+ g! l w( p9 p
但是,我必须提醒的是,如果你是小白,也就是说,你连常见的数据结构,如链表、树以及常见的算法思想,如递归、枚举、动态规划这些都没学过,那么,我不建议你盲目疯狂着去刷题的。而是先去找本书先去学习这些必要的知识,然后再去刷题。
$ Q. l) I! l* n0 ]* T8 ^( _% F4 b+ ?2 F/ B$ o3 C
因为,如果这些基础都不懂的话,估计一道题做了几个小时,然后看答案都看不懂,做题没有任何思路,这是很难受的。久而久之,估计没啥动力了,我刚开始就是这样,一道题答案看一天,然而还是不大懂,什么回溯啊,暴力啊,还不知道是啥意思。7 L2 R4 z( @3 ?! d: @* c
: g% m7 |! N7 o9 f1 H
也就是说,假如你要去诸如leetcode这些网站刷题,那么,你要先具备一定的基础,这些基础包括:7 T3 [ q+ x/ P6 [2 B( r
+ S* }! G$ P* p5 N, r4 R" y2 ^; j1、常见数据结构:链表、树(如二叉树)。(是的,链表和二叉树是重点,图这些可以先放着)
9 f& X2 N4 F8 V! C2 q
# ^4 ?5 K6 z3 e; v3 P4 o2、常见算法思想:贪婪法、分治法、穷举法、动态规划,回溯法。(贪婪、穷举、分治是基础,动态规划有难度,可以先放着)) u w/ f# N2 a! y
( H: `/ W }1 c/ c \: ]# W以上列出来的算是最基本的吧。就是说你刷题之前,要把这些过一遍再去刷题。如果你连这些最基本的都不知道的话,那么你再刷题的过程中,会很难受的,思路也会相对比较少。: _9 l( g1 s/ w2 I/ W" G
/ @* Z5 g# U9 U4 A: [5 Y总之,千万不要急,先把这些基本的过一遍,力求理解,再去刷题。
" `' F0 P+ O! ?( A) W+ {3 ]6 B0 T5 x% f7 W! [& L
在这里,我推荐基本我大一时看过的书籍吧,感觉还是非常不错的,如果对于数据结构时零基础的话,那么我建议你可以看《数据结构与算法分析:C语言描述版》这本书,这本书自认为真的很 nice,当时我把这本书里面的全部都看了,并且 coding 了一遍,感觉整个人有了质的飞跃。 |2 j1 ` J: P# I2 T) q5 g& p
$ C3 p, F" [' ?& K
后面我时在一些学校的OJ刷题,当时看的一本书叫做《挑战程序设计大赛》,日本作家写的,我觉得这本书也很nice,里面有分初级,中级和高级三个模块,基础比较差的可以从初级开始看起。
; _7 b: |4 n. h _$ z) F8 L0 J9 u3 L- U
当然,这两本书,你可以在这个Github上找到:https://github.com/iamshuaidi/CS-Book) f2 l0 T/ J- E+ J
总结下:3 b7 R/ P( K) u: H" k
! s! N! C* J% g" f3 j, q1 S. M
提高数据结构与算法没啥捷径,最好的捷径就是多刷题。但是,刷题的前提是你要先学会一些基本的数据结构与算法思想。
+ ~$ b. `2 O! F0 S; o2 d [1 ^2 ?* i8 v& C. m$ G( A, m
AC不是目的,我们要追求完美/ F) S9 \( R+ |9 U' |
! ? w" f' _! n* ]. w如何刷题?如何对待一道算法题?% W- |, \2 y3 Q: k( J5 b, H
7 }0 V; |# M# A, U* w; }我觉得,在做题的时候,一定要追求完美,千万不要把一道题做出来之后,提交通过,然后就赶紧下一道。我认为这意义不大,因为一道题的解法太多了,有些解法态粗糙了,我们应该要寻找最优的方法。
' Y, P6 {; G+ C% R" B3 `+ }7 t6 b% \5 @5 [/ y1 {# Q7 B
算法能力的提升和做题的数量是有一定的关系,但并不是线性关系。也就是说,在做题的时候,要力求一题多解,如果自己实在想不出来其他办法了,可以去看看别人是怎么做的,千万不要觉得模仿别人的做法是件丢人的事。1 }# o- {. |+ A, ^' E
& _3 p. g% m& o# E# B/ S我做题的时候,我一看到一道题,可能第一想法就是用很粗糙的方式做,因为很多题采用暴力法都会很容易做,就是时间复杂度很高。之后,我就会慢慢思考,看看有没其他方法来降低时间复杂度或空间复杂度。最后,我会去看一下别人的做法,当然,并不是每道题都会这样执行。
4 m& l1 C- {: ~; T! j8 H( T- _( H G2 G" f) h3 I" `
衡量一道算法题的好坏无非就是时间复杂度和空间复杂度,所以我们要力求完美,就要把这两个降到最低,令他们相辅相成。( P& i7 O! L0 j. e2 z- d. c
1 }" f. e5 Z6 R" L- c5 F我举道例题吧:- Q. L6 b# n1 d; X
7 Y6 H5 u" C3 P7 M( A1 {' R
问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?
$ H/ M; v/ P$ n$ R" C) q I, A$ x% s% i' [& N
这道题我在以前的分章分析过,不懂的可以先看下之前写的:递归与动态规划—基础篇1
5 W6 }5 e, Z- d% a8 f4 Q- U9 O8 C" ]# @9 v3 b5 z. O7 |
方法1::暴力递归1 T3 A' z; T5 A& x0 y8 z; @+ V
" I- p) j' q/ i' U& |这道题不难,或许你会采取下面的做法:) _' [, J7 j0 F. B' ? M$ m
2 L; @$ v K- \! K% B; r6 I" H3 z
public int solve(int n){* D- G3 j3 {. D% P
if(n <= 2){
% k2 T" Y% n: k+ r8 I9 d7 [ return n;( a4 e! @8 I" A; G1 {0 F. P
}else{
: [3 I, X: T9 g. ]9 M! v5 S6 E return solve(n-1) + solve(n-2);
6 J6 l6 }. @( O" o3 |8 \( Z: ? }
! s1 a, e0 y" ~" i}+ B* w0 X `5 e8 h: b% O5 g5 ?
1
+ N5 b$ F1 e, x# Q2+ e ?. K" e" w" v# l
3# n# K, j, D4 `3 G
4
( R- ], q! }% ?2 x# ?" i( U3 f5
) Q3 j$ [( O% P1 f1 X+ N6
0 \# A5 t% B! S' u) l$ t6 s8 V+ J7
) Y- V+ D0 Y+ J; q0 c4 j6 \" w这种做法的时间复杂度很高,指数级别了。但是如果你提交之后侥幸通过了,然后你就接着下一道题了,那么你就要好好想想了。+ d/ n p, h4 k+ C) [" u
" q+ a" p3 y3 g方法二:空间换时间! F8 z( S( _$ L
4 l7 G4 u3 A' l' N力求完美,我们可以考虑用空间换时间:这道题如何你去仔细想一想,会发现有很多是重复执行了。不行你可以画个图/ W* T5 G+ l, ]
- g, e+ t1 m/ ~9 X% F; |4 W; h6 K所以可以采取下面的方法:4 f+ p' p; t9 m2 \% e' l" f: x
; A7 B5 z! {) G3 h: U$ ^* q//用一个HashMap来保存已经计算过的状态4 ^/ K8 K# ~% E* G
static Map<Integer,Integer> map = new HashMap();# G# {+ K" S- d8 E4 v
public static int solve(int n){: P# r- _! g* k" O
if(n <= 2){" u5 f: P! E3 Q6 G! s# n* Z
return n;
+ f3 c6 r& a6 N5 g D; v0 K }else{//是否计算过5 s4 X2 L3 r* C# E
if(map.containsKey(n)){
$ B1 ], ^$ p, n1 [/ D return map.get(n);$ ~" x4 U E( z* [- }3 `8 R2 c3 I
}else{
# k! @9 i" M8 K1 }/ u7 j. r7 m: Y int m = solve(n-1) + solve(n-2);
, P H4 U& d& N; V5 z9 ~7 `5 q, D map.put(n, m);9 Y" }' D$ D; l) {
return m;
# r. p: V3 e! s$ W }
& A% k1 X! s' z0 ^& B! }/ N3 I7 X }
4 d# n' u6 B. F/ [' V}6 Y( h+ V9 ]& _$ V% y
8 I; ?5 F0 e/ S$ O15 e( B4 y" S1 P1 ~
2
. c8 c- A. b( x* N8 j3
4 B/ q z. N- ]( q) Z4! a) d7 F. l1 f) `# c/ K
5
& h$ F: l! W9 F$ T62 P. a/ P0 Y) O8 z O
75 ~, |( D7 c; o/ w: x
8
5 F/ V( K- u3 N1 \9+ G/ V% \, G5 T$ S1 M- E4 _6 e5 J! J
10
2 i" G+ ]" _% ?6 E) r/ K$ L7 ]11) e X# M7 q4 k- C P
12: w( N9 ~( }+ O2 h
13
7 L3 D' G8 q2 L+ E' |& l; b9 ]7 d4 ]14
0 [2 k$ @' u, b$ Q' j15; }, Y: T9 y* w
16; `; _) n! O+ Z
这样,可以大大缩短时间。也就是说,当一道题你做了之后,发现时间复杂度很高,那么可以考虑下,是否有更好的方法,是否可以用空间换时间。
6 ^2 x+ T# Z. Q, Y! r, f! c% f
- q$ X1 E+ V" U0 O方法三:斐波那契数列7 M7 j! }/ D+ T# x4 c
8 S8 h- M( Z# n" q+ C实际上,我们可以把空间复杂度弄的更小,不需要HashMap来保存状态:
$ K* X; h# N( d
# Q3 C# d" E! D+ wpublic static int solve(int n){ w$ h8 }& J! d2 u* ~
if(n <= 2){
! x( y- S- B7 ^; @1 S( g return n;
" o+ [# \4 a( P }
& f+ N3 \2 W* G% B3 Y4 \3 c int f1 = 0;; {: U4 @" K0 I7 q% S
int f2 = 1;6 n6 M! O& m8 U
int sum = 0;
: P( G L, h/ H# I" Y for(int i = 1; i<= n; i++){
3 p# v9 `2 x) r$ f" V; d sum = f1 + f2;: Z. j( q* {4 S% n
f1 = f2;
# ^: M. h& Q5 ]4 J$ |$ X, K* d! T f2 = sum;+ F5 ?0 m; L1 X: J+ H
}
3 v3 t- J# L, a0 P3 Z: S1 G return sum;
0 U& i" U0 ? D1 i" W$ {8 E5 R}
9 p( u7 c# V* `% M1* f# y# D: N4 V; Y5 K
2$ ]9 Y1 j) q8 A$ B$ m" c
39 y2 @. e7 k- W$ o' S
4; @1 |* i; Y' o( ~7 V" N3 Z8 W
5
7 i. I: q7 f2 ?) i( }6 r65 h, n% b! G0 C6 @/ o4 d7 w/ P
74 D* f3 ~; ]8 Z: ~
8 Y: e8 b0 N4 W1 @* K8 y) _8 E% x1 D @: s
9
% X2 U% Z7 k. ?% R' P- j106 n- I5 `3 N2 ~& }+ t
11
+ h, s- d1 p' l12
2 {$ S, ~! a$ i; L" ~8 \/ @13* p' B* D/ w3 o0 u5 i. B' D. m9 j
147 {# b. I7 o5 ^) e$ o
我弄这道题给你们看,并不是在教你们这道题怎么做,而是有以下目的:. h- Q" B: l1 r; ]7 c
3 O) l/ ?: |& m2 o: _1 ^
1、在刷题的时候,我们要力求完美。5 u# }" Z7 P x8 G! N: Q1 i, e
- N% D$ i/ u8 e9 G9 q9 r
2、我想不到这些方法啊,怎么办?那么你就可以去看别人的做法,之后,遇到类似的题,你就会更有思路,更知道往哪个方向想。 l! V6 ~. ^0 Y' `
, ]5 b9 T. q( ~6 v( K8 N3、可以从简单暴力入手做一道题,在考虑空间与时间之间的衡量,一点点去优化。
- q6 I5 t# \9 t6 l: C* E8 K8 W
, g) T% @' j+ v- X" i* }2 G挑战自己,跳出舒适区/ ]; }5 q' v5 }0 P8 V% b+ r+ U$ Z
1 ~2 G" d# r5 a* I) \$ _/ w# ~
什么叫舒适区?在刷题的时候,可能有一类题是你比较懂的,你每次一看就有思路,然后半个小时就撸好代码,提交代码,然后通过了,然后,哇,又多刷了一道题,心里很舒服。
% a3 G9 ] m5 I9 s6 K, W
+ v9 ]$ ^9 u5 h3 ~5 ~ L# n. K但是,记住,前期你可以多刷这种题练手,提升自己的乐趣,但,我还是建议你慢慢跳出舒适区,去做一些自己不擅长的题,并且找段时间一直刷这种题。例如,我觉得我在递归方面的题还是挺强的,
" \- }9 h+ m. _1 v6 p$ F& M9 e但是,我对动态规划的题,很菜,每次都要想好久,每次遇到这种题都有点害怕,没什么信心。不过有段时间我觉得只刷动态规划的题,直接在 leetcode 选定专题,连续做了四五十道,刚开始很难受,后来就慢慢知道了套路了,一道题从两三个小时最后缩到半小时,简单的十几分钟就搞定。感觉自己对这类型的题也不惧怕的。
3 f, Z$ a6 Y% A+ E8 r1 Z3 \$ x$ {( W0 b& b, f' Q0 n1 U( x
当然,对于动态规划的学习,大家也可以看我这篇广受好评的文章:为什么你学不过动态规划?告别动态规划,谈谈我的经验
* O$ I O, B% l1 F; t
$ I `3 C3 T& }; V; [所以,建议你,一定要学好跳出自己的舒适区。! A2 i, Z& l. I' D' b5 D' {
, G, m# g5 p# {$ ]4 _! X一定要学会分类总结7 ?1 h. e; N- R* Z8 g; J* R
5 e7 P& G) j, ?3 l' w
有些人以为 leetcode 的题刷的越多,就一定能越厉害,其实不然,leetcode 虽然有 1000 多道题,但题型就那么几类,我们前期在刷的时候,我是建议按照题型分类刷题的,例如我这整理刷二叉树相关,然后刷链表相关,然后二分法,然后递归等等,每刷一种题型,都要研究他们的套路,如果你愿意去总结,那么 leetcode 的题,其实你刷几百道,有目的、挑选的刷,我觉得就差不多了。
# g5 h& C+ S4 y) Z" a6 B2 {! ]4 V) [% c0 U, @+ d1 R' K" j
我看过一本书,叫做《程序员代码面试指南:IT 名企算法与数据结构题目最优解》,这本书就非常不错,里面按照栈,队列,链表,二叉树,字符串等一个专题一个专题来刷的,并且每道题都给出了最优解,而且里面的题有一定的难度,感兴趣的,真心不错,如果你把这本书的题全部搞定,并且总结相关套路,那么你的算法一定有很大的提升。
& E& _$ e6 n( E/ W2 I& z; [" c) E8 r: ]# f4 `
推荐一些刷题网站$ c4 ^$ {) x, y, e5 h9 g/ x: ?9 H7 q
* S# `. l0 ]( R" n1 V3 O" T" o$ ?, g( m
我一般是在leetcode和牛客网刷题,感觉挺不错,题目难度不是很大。, m" F( C- E7 E* b; N
" n) Y+ U; G. L: L
在牛客网那里,我主要刷剑指Offer,不过那里也有个在线刷leetcode,不过里面的题量比较少。牛客网刷题有个非常方便的地方就是有个讨论区,那里会有很多大佬分享他们的解题方法,不用我们去百度找题解。所以你做完后,实在想不出,可以很方便着去看别人是怎么做的。2 k3 K e$ B& b+ D: d2 w8 A
, _9 u/ h* Q; T! p5 ?; f _
至于leetcode,也是大部分题目官方都有给出答案,也是个不错的刷题网站。你们可以两个挑选一个,或者两个都刷。
6 c8 E9 @' Q' [3 M# R' Z2 m! H$ E4 E) ?5 A; Y
当然,还有其他刷题的网站,不过,其他网站没刷过,不大清除如何。" j. e# @$ U' C# _4 u7 g$ h
2 ]+ f7 E E; s
至于leetcode,有中文版和英文版0 ~/ _. _5 c$ ~8 E
% J& ^0 b6 s; g7 n# \& I1 bleetcode有中文版
% r( h" ?; }$ O6 A
- e* O$ e: ]4 l% j英文版# f5 H# }$ r/ V3 [; K' P! S+ R( g, @
- ~; V. A& _% k* u( n" v: u根据自己的兴趣选。, I+ G _. d5 j, |7 A
+ Q' t7 V6 e5 w2 @$ |学习一些解题技巧+ N* U+ \+ @. d: I' ^1 Z
6 R! _6 {- z0 V! q |/ D7 u说实话,有些题在你没看别人的解法前,你好不知道有这么美妙优雅的解法,看了之后,卧槽,居然还可以这样。而我们在刷题的过程中,就要不断累积这些技巧,当你累计多了,你就会形成一种$ N r# Q$ [: g: C5 T, T6 k
神经反应,一下子就想到了某种方法。解题技巧很多,例如数组下标法、位图法、双指针等等,我自己也分享过一篇总结一些算法技巧的文章3 f$ e1 ~3 U: J3 ~2 J- E- t
* {8 k% ]2 E; ~( h: M+ l& X; O
推荐阅读:一些常用的算法技巧总结9 n+ s7 k/ ^3 B' R" e3 T
' M# b% k' ^1 {( l" i& n
例如在刷题的时候,我们要学会巧用双指针、数组下标法、位运算等等技巧来解决问题,可能会有意想不到的效果。我给你再找点我之前写文章的一些例子吧:
7 P9 [# @ j' ~' v" G) I
, h5 t' U, l8 ]4 ^! u分享一道解法巧妙的算法题0 _- T) l5 \2 L& [9 X6 |
1 I( b( C$ N) z9 @+ W% a0 h
【算法技巧】位运算装逼指南+ b9 b9 q& e8 R& m2 T9 E
7 O) _3 d `3 v9 a7 t
这是个长期累积的过程,我自己也精彩在我的公众号里分享一些解题的文章,感兴趣的可以关注我的公众号:帅地玩编程。
7 F" ] E7 p+ M, c! W& @7 l: ?# w$ E4 r* o+ V5 p/ ]1 {- _9 E) N
再说数据结构发重要性4 a4 V0 R/ }2 r
5 g5 m, n1 I; ^6 h) b% C7 e# R; X
前面我主要是说了我平时都是怎么学习算法的。在数据结构方法,我只是列举了你们一定要学习链表和树(二叉堆),但这是最基本的,刷题之前要掌握的,对于数据结构,我列举下一些比较重要的:
; s( z: j1 {2 \# O% ?' s( j* @- [& ]& k: s* C
1、链表(如单向链表、双向链表)。
1 y. J, D9 e n0 h7 u- t( a+ p
3 l3 z4 M( q/ h$ O2、树(如二叉树、平衡树、红黑树)。
8 N e- \ i' a7 ?& F j [# u7 K; d, J ]" N9 y3 T
3、图(如最短路径的几种算法)。: a; M* j3 b6 L9 G
; y2 u+ u/ @. Y1 P
4、队列、栈、矩阵。" `7 [. e7 D8 m4 _2 t
% O/ k8 n; S2 I' U) }对于这些,自己一定要动手实现一遍。你可以看书,也可以看视频,新手可以先看视频,不过前期可以看视频,之后我建议是一定要看书。. i" B; _ y6 M4 l# h; u H
" @; B3 |8 E! X5 G& a" b8 w& T例如对于平衡树,可能你跟着书本的代码实现之后,过阵子你就忘记,不过这不要紧,虽然你忘记了,但是如果你之前用代码实现过,理解过,那么当你再次看到的时候,会很快就记起来,很快就知道思路,而且你的抽象能力等等会在不知不觉中提升起来。之后再学习红黑树啊,什么数据结构啊,都会学的很快。
+ R1 x) _3 Q* \+ ^% l& T9 h# z6 i: R6 F
对于有哪些值得学习的算法,我之前也总结过,这里推荐给大家程序员必须掌握的核心算法有哪些?,这篇文章居然 40多万阅读量了,有点受宠若惊。; N0 x" s, @6 Z7 w3 M
& F+ a* b) B* y8 j# `$ I/ O
最最重要
9 i& u `$ d" v+ L+ [" X9 `6 E' q9 K5 v, n1 s$ ^
动手去做,动手去做,动手去做。重要的话说三遍。
) |( U% w; v& U; j0 G
! b9 B+ f* W: J) @千万不要找了一堆资源,订好了学习计划,我要留到某某天就来去做…# m" Z! _5 P2 c1 @4 S# t
& W; M7 o7 ?& X! H/ `千万不要这样,而是当你激情来的时候,就马上去干,千万不要留到某个放假日啊什么鬼了,很多这种想法的人,最后会啥也没做的。
; Q! A: T0 w) k0 U" Y6 V% d" o6 b2 Q3 T. a
也不要觉得要学习的有好多啊,不知道从哪学习起。我上面说了,可以先学习最基本的,然后刷题,刷题是一个需要长期坚持的事情,一年,两年。在刷题的过程中,可以穿插和学习其他数据结构。
5 |' j# q% e- B k; M; x
. K; U. z: ?; ?' l* B& n s6 R. i总结一下吧. e( X) a; M8 t; j5 L- `& h, H
2 G9 B/ E7 |/ G N2 N所以我给大家的建议就是,先学习基本的数据结构以及算法思想,不要盲目刷题,接着刷题的过程中,不能得过且过,尽量追求最优解,还有就是要跳出舒适区,逼自己成长,刷题的过程中,要学会分类总结。/ }( I4 e7 C' o& j
, [+ Y1 H3 _; j( H* y, j
当然,最重要的,就是你去动手了,不然,一切免谈!+ c2 ^& ?' _: X; c6 k
" H. i6 E$ M/ O$ v6 I+ m& y看在熬夜写过的份上,送我个赞呗,嘻嘻。' X6 x# d; ^) U+ E1 L8 u' Y
————————————————
. O( |2 g7 h- ?+ W% S- w版权声明:本文为CSDN博主「帅地」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。5 A$ B0 o6 t1 n& z
原文链接:https://blog.csdn.net/m0_37907797/article/details/104765116
) M2 M" x; d* S. `+ z- J+ H6 u4 \4 I, q1 {
" s8 Z$ K8 p2 f$ d
|
zan
|