- 在线时间
- 1630 小时
- 最后登录
- 2024-1-29
- 注册时间
- 2017-5-16
- 听众数
- 82
- 收听数
- 1
- 能力
- 120 分
- 体力
- 563399 点
- 威望
- 12 点
- 阅读权限
- 255
- 积分
- 174243
- 相册
- 1
- 日志
- 0
- 记录
- 0
- 帖子
- 5313
- 主题
- 5273
- 精华
- 3
- 分享
- 0
- 好友
- 163
TA的每日心情 | 开心 2021-8-11 17:59 |
|---|
签到天数: 17 天 [LV.4]偶尔看看III 网络挑战赛参赛者 网络挑战赛参赛者 - 自我介绍
- 本人女,毕业于内蒙古科技大学,担任文职专业,毕业专业英语。
 群组: 2018美赛大象算法课程 群组: 2018美赛护航培训课程 群组: 2019年 数学中国站长建 群组: 2019年数据分析师课程 群组: 2018年大象老师国赛优 |
2 T, ^& N* K ~" L% e( a
算法越学越扎心,有没啥破解之法?4 p/ m9 C; g3 _
算法越学越扎心,有没啥破解之法?
) x. Y8 ^ z7 F! A& G$ m
5 p% Q6 U6 J7 p对于算法的学习,我也是从一个小白一步步走来,当然,现在仍然很菜,,,不过,鉴于我觉得还有一些人比我更菜了,我决定谈谈我算法学习过程走过的坑,以及自己总结的一些经验。
( D5 j: v! W" C. Y" z- c
$ m* t( P J/ u& o切勿盲目刷题:刷题前的知识积累% A) ^. Y1 @0 W4 Q7 x0 Z9 R% |
5 s Z1 o* Y1 c+ l' [9 V; S说实话,想要提高自己的算法,真的没啥捷径,我觉得最好的捷径就是脚踏实地着多动手去刷题,多刷题。
% [+ P' K0 M0 i3 R5 e1 I
4 z+ z w# u- J# O2 D但是,我必须提醒的是,如果你是小白,也就是说,你连常见的数据结构,如链表、树以及常见的算法思想,如递归、枚举、动态规划这些都没学过,那么,我不建议你盲目疯狂着去刷题的。而是先去找本书先去学习这些必要的知识,然后再去刷题。. N: U5 o% z. z4 x# V2 D" f
$ a% x- D: d8 Y) p5 R8 n: b
因为,如果这些基础都不懂的话,估计一道题做了几个小时,然后看答案都看不懂,做题没有任何思路,这是很难受的。久而久之,估计没啥动力了,我刚开始就是这样,一道题答案看一天,然而还是不大懂,什么回溯啊,暴力啊,还不知道是啥意思。
9 B' L$ D! {. {) J. `' }% [7 U( W- b) ?' H6 h, Q4 d
也就是说,假如你要去诸如leetcode这些网站刷题,那么,你要先具备一定的基础,这些基础包括:
6 D6 }* g# y* m2 _" L3 F' e% l& q) c! B) ]( t0 w
1、常见数据结构:链表、树(如二叉树)。(是的,链表和二叉树是重点,图这些可以先放着)
6 U% C; c' ?6 g. Q1 s' V% Z
' j, y5 d) ?) r2、常见算法思想:贪婪法、分治法、穷举法、动态规划,回溯法。(贪婪、穷举、分治是基础,动态规划有难度,可以先放着)
: l! u2 k/ [0 g! Q# a, V+ q0 U% _5 s4 I
1 @( b8 ~4 ?% K$ [5 m1 {1 S以上列出来的算是最基本的吧。就是说你刷题之前,要把这些过一遍再去刷题。如果你连这些最基本的都不知道的话,那么你再刷题的过程中,会很难受的,思路也会相对比较少。6 R; X; W- l: e0 Z4 ^) T& }
6 q4 D3 A- l5 [- v
总之,千万不要急,先把这些基本的过一遍,力求理解,再去刷题。6 o# @8 [! s3 Q) C6 r
9 U3 L$ \8 O+ J5 o( R在这里,我推荐基本我大一时看过的书籍吧,感觉还是非常不错的,如果对于数据结构时零基础的话,那么我建议你可以看《数据结构与算法分析:C语言描述版》这本书,这本书自认为真的很 nice,当时我把这本书里面的全部都看了,并且 coding 了一遍,感觉整个人有了质的飞跃。
( }& t2 G. ?" P' u3 q: q3 B1 W" y2 L5 ~" L% _- c
后面我时在一些学校的OJ刷题,当时看的一本书叫做《挑战程序设计大赛》,日本作家写的,我觉得这本书也很nice,里面有分初级,中级和高级三个模块,基础比较差的可以从初级开始看起。
# \0 D) h6 V" p/ \' A
3 w5 A! J; ^! a3 Q* q当然,这两本书,你可以在这个Github上找到:https://github.com/iamshuaidi/CS-Book
' Y U' _4 |' y4 K, y$ v: Y总结下:. g d; [: m, x. z* k
% g M n9 U/ z* G3 x8 q提高数据结构与算法没啥捷径,最好的捷径就是多刷题。但是,刷题的前提是你要先学会一些基本的数据结构与算法思想。
" @. N" ^ p4 J" R0 W
" B+ d* H" C |! V# j& D1 YAC不是目的,我们要追求完美
8 ~7 _+ q; w6 {0 i! H
$ @( N& v) w! e- F如何刷题?如何对待一道算法题? ?; c+ ^# i+ _, N& z; R# ?; I, p
' r; o& ~7 d6 v我觉得,在做题的时候,一定要追求完美,千万不要把一道题做出来之后,提交通过,然后就赶紧下一道。我认为这意义不大,因为一道题的解法太多了,有些解法态粗糙了,我们应该要寻找最优的方法。8 a2 ? g( }* c/ w5 m
S0 C! V( I m" m9 X算法能力的提升和做题的数量是有一定的关系,但并不是线性关系。也就是说,在做题的时候,要力求一题多解,如果自己实在想不出来其他办法了,可以去看看别人是怎么做的,千万不要觉得模仿别人的做法是件丢人的事。, ^5 V" l' N2 d! q! X$ T
: K* ]' c4 V; {( J, a2 b5 R: X
我做题的时候,我一看到一道题,可能第一想法就是用很粗糙的方式做,因为很多题采用暴力法都会很容易做,就是时间复杂度很高。之后,我就会慢慢思考,看看有没其他方法来降低时间复杂度或空间复杂度。最后,我会去看一下别人的做法,当然,并不是每道题都会这样执行。* n$ ]' h9 F: u- |; Z+ D! F
* k6 A" ]2 I6 Q- e! _
衡量一道算法题的好坏无非就是时间复杂度和空间复杂度,所以我们要力求完美,就要把这两个降到最低,令他们相辅相成。
3 W, o* p4 `! ^% v; d* n- F9 z: {. Y0 M& ?
我举道例题吧:: e$ H9 W! |7 g; h& N
8 _ U8 Z: Z# S! ]5 G1 Z
问题: 一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法?$ c6 a- G8 a3 Q
3 Q$ x4 ]. }5 i7 ~. ?
这道题我在以前的分章分析过,不懂的可以先看下之前写的:递归与动态规划—基础篇1
# E: J1 Z; \0 [/ \$ `( b) N; v* Q' C4 d, T
方法1::暴力递归
" @' N$ i% C4 W* Y! p8 | O* x/ P5 Q2 j$ O& K3 ^ o
这道题不难,或许你会采取下面的做法:
1 u' }9 M: ]1 J0 b: f, p, V* \/ Q% T5 }
public int solve(int n){
2 [! ~1 Q0 A' S h. d if(n <= 2){
. B+ F* Q' H" j! @* I: k7 c8 x return n;! w m; m- g: D% z
}else{
" X" V; J* C, V$ _% W) r return solve(n-1) + solve(n-2);
1 t9 W2 L7 k. w3 t- I9 t7 S) w }$ }' B3 n, @+ T" b* [+ o
}6 C- i! n( ?1 ?4 Q
1( X( U' @2 _& b- U
2: Q4 F" j$ j3 V) i1 R0 ]
3
, m5 ~9 A; i/ B& x4 W( n4
% j9 }# {/ c3 Y5
! P# |1 Y6 p2 X5 q63 a4 M9 v G2 \& q. o N$ y
71 k: f. m$ j1 G& E
这种做法的时间复杂度很高,指数级别了。但是如果你提交之后侥幸通过了,然后你就接着下一道题了,那么你就要好好想想了。) h# W" Z" \( h, t7 h! T2 O! x
, {+ u3 G% g3 ~! d1 W方法二:空间换时间
1 ]7 t: w4 K5 v* D3 Y
. l* s2 ]/ Q' c$ l( x力求完美,我们可以考虑用空间换时间:这道题如何你去仔细想一想,会发现有很多是重复执行了。不行你可以画个图
9 F$ h( G# d: y, J/ X M- v& Q5 ^9 J4 H
所以可以采取下面的方法:
* v" O' x: d- S2 j
) {) t0 h& r3 m/ D% f//用一个HashMap来保存已经计算过的状态! \$ B0 |, J9 j
static Map<Integer,Integer> map = new HashMap();
2 `4 e: Q' W& hpublic static int solve(int n){
, e! t7 v6 l. a! m, s if(n <= 2){
( y7 I. x6 L' ~' i return n;
' h- I2 t; v5 X0 I }else{//是否计算过
# s9 _( E0 p! M3 }6 W a- n8 u if(map.containsKey(n)){
- Z# ~8 a0 G o3 a6 r3 S8 M1 A return map.get(n);
+ \ F5 C3 H3 d* U- A" U, h }else{+ R4 F7 Q3 H3 I; a1 @; I7 g
int m = solve(n-1) + solve(n-2);
" G* q. h d8 G0 j8 E | map.put(n, m);
; R0 u1 Z, L3 O. ]8 _ j return m;/ O& ~5 ~7 L/ ~
}
. S4 M! Y4 G8 X# o) W }
9 b( p4 _) q2 U, f1 E}0 q# t( v7 m) F$ j" l
% b# x( i: ^1 Z! e2 Z1. w8 \ m0 p; }; N' D
2" u3 _6 h+ a+ J i
3
' ?, v. ^) }3 e+ d4
' s2 d* ~$ N/ `% V6 q! |5
0 B* u$ s; z3 F X4 S. U! j6# R3 G& h5 M" A0 j i2 c
7; I4 O) q7 c7 {
8
- p! o- F1 T( \) |+ \1 a9" p6 ~8 R0 P: X& s$ V
104 I7 }7 k9 k( C% s0 _
11
* g1 e5 ^; k5 ?+ T7 V4 W* o12, z9 q9 m1 x9 r& H% ?# `
13
- U! p( _& k, d# T `9 T* w |14
, |# s, |) A4 S4 E; K7 O15/ T# u8 ?+ s4 e6 a
163 I* z1 m8 [* E# k
这样,可以大大缩短时间。也就是说,当一道题你做了之后,发现时间复杂度很高,那么可以考虑下,是否有更好的方法,是否可以用空间换时间。
) V7 R$ i& ]: b! d" [
8 X/ k3 D& ?8 D7 P方法三:斐波那契数列2 L5 Y: z5 V+ Y' p/ [
/ v% @* S+ R A# n7 E9 V; J实际上,我们可以把空间复杂度弄的更小,不需要HashMap来保存状态:: Q" [, B* v7 A/ f
0 X. K% P0 w1 I2 y* [! K+ e
public static int solve(int n){
7 e, c( ]9 p1 ]; i* H# U6 |: o if(n <= 2){
* `3 D8 c- R$ V return n;$ S2 d' E8 C" Q5 ~) M$ d7 S
} - k' y- Q; D3 {
int f1 = 0;1 s0 r" H1 r& o9 g
int f2 = 1;
$ @) U( L9 X2 p: Z' p6 z3 ?/ _ int sum = 0;; T$ n9 T; `6 q% o& i+ U! |, ~
for(int i = 1; i<= n; i++){' z( a9 L6 C- O/ K& u
sum = f1 + f2;! v; I1 T9 s4 o
f1 = f2;
5 }9 G/ ^4 x# j1 ^- `* E. g/ ?) o f2 = sum;8 ?( c# R6 f; ]& [4 l
}! g: X5 ]' q, K! W! X, r: h# p
return sum;
) P$ ^# S; b2 w' H+ [2 q1 L}
' H& W9 N1 J, K9 R! l+ F14 z$ J9 ?9 H# t! O( f" x) ?4 y) `* L- }
2
. H5 i i4 Y* S4 o3- r/ h+ _+ R/ G! A7 G: I
4% M& s! L" M4 ^- }. x. S
5& G' P" C# W2 f2 _! x# U! w
6
! n9 `$ \/ `7 o/ ~' @# h75 q, R* I' I& C+ b9 [% d7 f
8. E6 w0 |- w( W9 B5 ?& Z$ b
9" M+ o# g! [4 L' n2 {8 c
10
5 r5 }+ L$ A4 V11
6 n }+ J9 u% W127 f! L& p0 K0 }8 X6 Z
13, r* X; G3 P' j$ p
141 F. c/ K Y& ]) o
我弄这道题给你们看,并不是在教你们这道题怎么做,而是有以下目的:3 X$ a+ B) r7 u- r. ^
3 w% K5 t; E3 B& U& p3 N1、在刷题的时候,我们要力求完美。) A/ `" v( ?% D9 O; ]) a$ m
+ X9 [& d) J0 \/ J: D2、我想不到这些方法啊,怎么办?那么你就可以去看别人的做法,之后,遇到类似的题,你就会更有思路,更知道往哪个方向想。0 T3 M% ?" }% d
p3 l* S# d" E% p1 W0 _$ a
3、可以从简单暴力入手做一道题,在考虑空间与时间之间的衡量,一点点去优化。
6 S) }) X) m. J3 H+ R( A
7 H' D8 D8 I' T x6 A" j挑战自己,跳出舒适区1 U0 V2 K% \7 r$ g `1 x
: U5 e+ o0 U/ P2 p# z
什么叫舒适区?在刷题的时候,可能有一类题是你比较懂的,你每次一看就有思路,然后半个小时就撸好代码,提交代码,然后通过了,然后,哇,又多刷了一道题,心里很舒服。5 D( ^9 i m6 T' k9 v% w9 H6 o
# g0 Y! c4 v+ C, j4 W8 @
但是,记住,前期你可以多刷这种题练手,提升自己的乐趣,但,我还是建议你慢慢跳出舒适区,去做一些自己不擅长的题,并且找段时间一直刷这种题。例如,我觉得我在递归方面的题还是挺强的,
% u0 @: G& O B Z3 e0 n" L但是,我对动态规划的题,很菜,每次都要想好久,每次遇到这种题都有点害怕,没什么信心。不过有段时间我觉得只刷动态规划的题,直接在 leetcode 选定专题,连续做了四五十道,刚开始很难受,后来就慢慢知道了套路了,一道题从两三个小时最后缩到半小时,简单的十几分钟就搞定。感觉自己对这类型的题也不惧怕的。
: U0 S1 p; C# W! o ^' L& ]$ E* T$ f( k1 ^/ o+ J% |4 r1 N
当然,对于动态规划的学习,大家也可以看我这篇广受好评的文章:为什么你学不过动态规划?告别动态规划,谈谈我的经验
: S8 F& G- a/ G* Y& m! [+ F
) } v" M! N0 T0 x所以,建议你,一定要学好跳出自己的舒适区。
6 G8 G F* ~. o/ Q( Q/ r: f& Y# t
一定要学会分类总结/ Y7 r+ u$ ]7 c+ Q
7 e, c" V5 r0 {( T
有些人以为 leetcode 的题刷的越多,就一定能越厉害,其实不然,leetcode 虽然有 1000 多道题,但题型就那么几类,我们前期在刷的时候,我是建议按照题型分类刷题的,例如我这整理刷二叉树相关,然后刷链表相关,然后二分法,然后递归等等,每刷一种题型,都要研究他们的套路,如果你愿意去总结,那么 leetcode 的题,其实你刷几百道,有目的、挑选的刷,我觉得就差不多了。1 D' \+ W7 v2 @6 _& h
; f2 I: E7 L, W% o! _& y我看过一本书,叫做《程序员代码面试指南:IT 名企算法与数据结构题目最优解》,这本书就非常不错,里面按照栈,队列,链表,二叉树,字符串等一个专题一个专题来刷的,并且每道题都给出了最优解,而且里面的题有一定的难度,感兴趣的,真心不错,如果你把这本书的题全部搞定,并且总结相关套路,那么你的算法一定有很大的提升。" a: f/ G8 w, V! b
, L- Y) s; k) I9 ?! L0 j
推荐一些刷题网站
9 k, q4 E- M) |" U% I) o( L" b( z9 B m
我一般是在leetcode和牛客网刷题,感觉挺不错,题目难度不是很大。' S# w+ G; D6 w6 |! t
" J" Q3 w4 [# t) a在牛客网那里,我主要刷剑指Offer,不过那里也有个在线刷leetcode,不过里面的题量比较少。牛客网刷题有个非常方便的地方就是有个讨论区,那里会有很多大佬分享他们的解题方法,不用我们去百度找题解。所以你做完后,实在想不出,可以很方便着去看别人是怎么做的。2 e8 A' ^% m1 J( [, {$ u- T
+ O9 o( `, y- N P# ^+ y& S. K: C至于leetcode,也是大部分题目官方都有给出答案,也是个不错的刷题网站。你们可以两个挑选一个,或者两个都刷。 ]5 N0 B" K( m
- J: B( l& \: g8 w- K& p当然,还有其他刷题的网站,不过,其他网站没刷过,不大清除如何。
, N6 s# h3 P8 w" b9 W8 a) A% Y' s. W4 C
至于leetcode,有中文版和英文版% N9 P, z6 {1 B
8 S5 K6 K+ H. Y" d8 X1 _! V
leetcode有中文版- c0 x7 H. @' ?: x4 s
7 w) ~: m( y4 P: |
英文版
7 r. ^' k! O" L% K( }3 v
# R9 G9 S" Q6 x5 I$ |: E3 \# D' ?+ w根据自己的兴趣选。
: D% A2 `0 {- c* \+ M. o+ ?6 T# p) t/ v
学习一些解题技巧( E& O8 c) n: f" o( K
5 t4 J0 E& C6 G @" P& E
说实话,有些题在你没看别人的解法前,你好不知道有这么美妙优雅的解法,看了之后,卧槽,居然还可以这样。而我们在刷题的过程中,就要不断累积这些技巧,当你累计多了,你就会形成一种+ j/ k2 n7 A$ P/ }
神经反应,一下子就想到了某种方法。解题技巧很多,例如数组下标法、位图法、双指针等等,我自己也分享过一篇总结一些算法技巧的文章; s% v4 i( P* H
! [- W+ F0 X k% p) D. ?3 V" H9 }
推荐阅读:一些常用的算法技巧总结 J: k* |# E( v7 Q
' I5 _ j+ G5 E- @0 o7 U
例如在刷题的时候,我们要学会巧用双指针、数组下标法、位运算等等技巧来解决问题,可能会有意想不到的效果。我给你再找点我之前写文章的一些例子吧:! v; I. R# r3 v" _% Q
0 \4 u' {8 G4 ^, d! P5 {2 u分享一道解法巧妙的算法题 N# u7 E& p( Q3 w: X4 ~
! J- q, y$ w4 a, a( d7 F% ?# s【算法技巧】位运算装逼指南% Q$ H8 W- l, n/ e, w( S ?
& T+ m( O/ d- N4 t, `
这是个长期累积的过程,我自己也精彩在我的公众号里分享一些解题的文章,感兴趣的可以关注我的公众号:帅地玩编程。/ {% d* U$ a5 D8 |; o8 F V( K7 F
* d5 N* ^9 n; _4 b+ G1 P
再说数据结构发重要性
5 h1 Q2 r. _% G
+ b$ [% v# P3 ]5 n1 z6 U8 ~前面我主要是说了我平时都是怎么学习算法的。在数据结构方法,我只是列举了你们一定要学习链表和树(二叉堆),但这是最基本的,刷题之前要掌握的,对于数据结构,我列举下一些比较重要的:
. Q! R3 ^+ r2 J' `
. P4 P- k E$ f4 r1、链表(如单向链表、双向链表)。, }8 r! r* R/ }: x# ~
9 t1 E8 _; S( T/ i2、树(如二叉树、平衡树、红黑树)。7 }/ l! ]. a' P; j) ]1 P$ N* r: A
3 ^; L% `& C; G' {/ W* E
3、图(如最短路径的几种算法)。! i, v H/ z( J$ M8 z: b3 C/ f
7 u1 k, ?. a) S' G# x- ^/ ` I4、队列、栈、矩阵。; a6 b. i4 t d j) B! R4 b+ q" b
, k; Z' T" j/ ]/ {
对于这些,自己一定要动手实现一遍。你可以看书,也可以看视频,新手可以先看视频,不过前期可以看视频,之后我建议是一定要看书。
- I8 X, @) s: d" a0 g
1 l/ H' ^; E, U+ U6 K6 d' I例如对于平衡树,可能你跟着书本的代码实现之后,过阵子你就忘记,不过这不要紧,虽然你忘记了,但是如果你之前用代码实现过,理解过,那么当你再次看到的时候,会很快就记起来,很快就知道思路,而且你的抽象能力等等会在不知不觉中提升起来。之后再学习红黑树啊,什么数据结构啊,都会学的很快。
! B1 T* H1 Y- o8 h* R8 |; n: Y2 |% L5 x) P0 `( Q9 I& D9 y
对于有哪些值得学习的算法,我之前也总结过,这里推荐给大家程序员必须掌握的核心算法有哪些?,这篇文章居然 40多万阅读量了,有点受宠若惊。* [- C% C, g: `/ Z% \
" P# T2 |, q' s8 b( `
最最重要; ?) u8 \% L" J5 {$ m: ~+ E
/ Q, \! U+ R: g1 S$ X, [" M
动手去做,动手去做,动手去做。重要的话说三遍。! b! ^) O3 ~9 Y! I$ F$ ^2 P+ H
, U! z8 B3 r' x' H( `% T
千万不要找了一堆资源,订好了学习计划,我要留到某某天就来去做…
! [4 `0 X: `7 M8 ~" F7 X' i0 D0 q2 W5 ~9 s0 S
千万不要这样,而是当你激情来的时候,就马上去干,千万不要留到某个放假日啊什么鬼了,很多这种想法的人,最后会啥也没做的。) L% v. H8 v$ e& t0 n3 A" V
# z. I! X1 s* @- B, v( D也不要觉得要学习的有好多啊,不知道从哪学习起。我上面说了,可以先学习最基本的,然后刷题,刷题是一个需要长期坚持的事情,一年,两年。在刷题的过程中,可以穿插和学习其他数据结构。
! a, h) t+ R4 ~6 y2 U+ I8 X% H2 [# e) N. ?; V
总结一下吧, n E( z$ v- m1 u
3 W; c |; i1 F& W所以我给大家的建议就是,先学习基本的数据结构以及算法思想,不要盲目刷题,接着刷题的过程中,不能得过且过,尽量追求最优解,还有就是要跳出舒适区,逼自己成长,刷题的过程中,要学会分类总结。
5 K% @9 J; a( v. t: Q% F5 B
8 @6 p U( O" V9 k) O% H当然,最重要的,就是你去动手了,不然,一切免谈!; {( b; g% u$ y" G9 H# I* k( P
a: H6 }9 A- E/ V- b看在熬夜写过的份上,送我个赞呗,嘻嘻。
5 n& h% b3 v( i————————————————; \+ S. p9 y7 B* F/ B3 W
版权声明:本文为CSDN博主「帅地」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。2 T8 i- P* Z* Q$ Z
原文链接:https://blog.csdn.net/m0_37907797/article/details/104765116* {+ j- \* \$ \: X! ^
6 z2 H3 R3 U; F
# T# x; S1 R: n! M
|
zan
|