Competitive Programming: From Basics to Mastery

注:本文为 "Competitive Programming" 相关合辑。

英文引文,机翻未校。

如有内容异常,请看原文。


A Guide to Competitive Programming

竞技编程指南

r/csMajors • 3 years ago

This guide consists of several subsections: my background, introductory steps, practice resources, study resources, practice methods, and answering common questions about competitive programming.

本指南包含几个部分:我的背景、入门步骤、练习资源、学习资源、练习方法以及回答有关竞技编程的常见问题。

My Background and Disclaimers:
我的背景及免责声明:

A quick disclaimer: I am not some genius competitive programmer. In fact, I consider myself to be beginner/intermediate, given that I have been doing it for ( < 10 ) months in total now (not continuously - I stopped for a year and a half in between, doing no programming during this time). So, by no means am I an expert on this topic - if anyone feels like I have missed something in this guide (which I certainly have), do leave a comment! That being said, I think that I'm a good person to be writing this guide because when I started competitive programming, I had zero knowledge of programming and virtually no math background. Many successful competitive programmers you will come across have been coding from a young age and/or doing math competitions (e.g., IMO) for years prior to starting, and so trying to follow what they did to "get good" will probably just not work for you (unless you share such a background).

快速声明一下:我不是什么天才竞技程序员。实际上,考虑到我总共只做了不到 10 个月的竞技编程(不是连续的------中间停了一年半,期间完全没写代码),我自认为还处于初学者/中级水平。所以,我绝不是这个领域的专家------如果有人觉得我在本指南中遗漏了什么(这肯定有),请一定要留言!话虽如此,我觉得自己写这份指南还挺合适的,因为我开始竞技编程时,对编程一无所知,数学基础也几乎为零。许多你遇到的成功竞技程序员,要么从小就开始编程,要么在开始之前已经参加了多年的数学竞赛(比如国际数学奥林匹克竞赛),所以,试图照搬他们"变强"的方法,对你来说可能根本行不通(除非你也有类似的背景)。

But chances are, if you are reading this, you know some programming and/or math, and so pretty much everything I mention here will be either applicable to you or beneath you (so to speak). I guess I should prove that these techniques worked for me - using them, I was able to go from zero to Google Kickstart top 50, winning prizes, placing first/second nationally in big competitions, ICPC, etc. in not too long. (Not trying to flex at all - actually, my achievements aren't anything impressive compared to other competitive programmers - it's just that these sort of posts usually contain something like this)

但很有可能,如果你在看这篇文章,你已经懂一些编程和/或数学了,所以我提到的大部分内容要么对你有用,要么对你来说太基础了(这么说吧)。我想我应该证明这些方法对我是有效的------用了这些方法,我从零基础很快就能进入谷歌启动赛前 50 名,赢得奖金,在大型比赛中获得全国第一/第二名,参加国际大学生编程比赛等。 (绝对不是在炫耀------实际上,和其他竞技程序员相比,我的成就并不值得一提------只是这类帖子通常会包含类似的内容。)

Another disclaimer: I do not mention USACO anywhere in this blog . The reason: I simply have never used it. I have heard some excellent things about it, though, so if anyone would like to add USACO-specific comments, please do!

另一个声明:我在博客中没有提到美国计算机奥林匹克竞赛(USACO)。原因很简单:我从来没用过。不过,我听说过它的一些优点,所以如果有人想补充关于 USACO 的具体评论,请尽管说!

So, how do I start? And what is competitive programming?
那么,我该如何开始?竞技编程到底是什么?

Before you read any further, watch this video from William Lin if you haven't already. It's great at answering questions you may have, and William also goes over his tips for beginners. So what's the purpose of this post then? Well, the video is a bit outdated in my opinion - I have some stuff to add. Also, William can be classed as one of those "competitive programming geniuses" I mentioned earlier. There is also this video, by another YouTuber called Errichto, that I also recommend.

在继续阅读之前,请先观看威廉·林的这个视频,如果你还没看过的话。它很擅长解答你可能有的问题,威廉还分享了他给初学者的建议。那么,这篇文章的目的是什么呢?在我看来,这个视频有点过时了------我有一些补充内容。而且,威廉可以被归为我之前提到的那些"竞技编程天才"之一。此外,我还推荐另一个 YouTuber 叫做 Errichto 的视频

After you've watched the video(s), there's one thing I want to add right off the bat - don't focus on typing speed as a beginner. It's simply not important if you're starting out - solving problems is much, much more worth your time at this stage, in my opinion. There are Legendary Grandmasters (LGMs on Codeforces - more on this platform later) who type with two fingers, after all. I am not going to elaborate more on what competitive programming is, what big competitive programming contests there are, etc. as these are all either Google-able questions or have been answered in the videos linked above. As for my thoughts on how to start competitive programming, keep reading...

看完视频后,我马上要补充一点------初学者不要专注于打字速度。如果你刚开始,这根本不重要------在我看来,解决问题要值得你花更多时间。毕竟,有些传奇大师(Codeforces 上的 LGM------稍后会详细介绍这个平台)打字只用两根手指。我不再详细阐述竞技编程是什么,有哪些大型竞技编程比赛等,因为这些问题要么可以谷歌搜索,要么在上面链接的视频中已经回答过了。至于我关于如何开始竞技编程的想法,请继续往下读......

Practice Resources
练习资源

Let's now get into resources you can use to practice (ie solve problems). Interestingly, everyone says the same thing - when you start off, it does not matter what resource you use . At the beginning, you are still developing basic competences and learning basic techniques, and so the platform you use doesn't matter as long as it's a decent one (and one with easy problems, of course). William mentions Hackerrank in his video. Other people use HackerEarth, Codechef, or LeetCode even.

现在我们来谈谈你可以用来练习(也就是解决问题)的资源。有趣的是,每个人都说同样的话------刚开始时,你用什么资源并不重要。一开始,你还在培养基本能力,学习基本技巧,所以只要是个不错的平台(当然,得有简单的问题),用什么平台都行。威廉在他的视频中提到了 Hackerrank。还有人用 HackerEarth、Codechef,甚至 LeetCode。

But I want to talk a bit about the two platforms that have helped me the most (and probably the two biggest platforms at the moment) - Codeforces and AtCoder. I am sure many of you have heard of Codeforces, and what William says about it and how to use it is great. So, I will speak about AtCoder in more depth - I think it is a brilliant platform. The great thing about it is it's immediately accessible . Yes, you, reading this, if you know just a tiny bit of a programming language, you can go to the AtCoder website, pick an ABC (AtCoder Beginner Contest), and have a good shot at solving the first two problems, which are designed to be accessible to everyone. If you can't, read the editorial. Rinse and repeat (more about this method is to come in the "How to Practice" section), solving all problems that you can each time, and you'll quickly see improvement.

但我还想谈谈对我帮助最大的两个平台(也是目前最大的两个平台)------Codeforces 和 AtCoder。我相信你们很多人都听说过 Codeforces,威廉关于它以及如何使用它的说法非常棒。所以,我想更深入地谈谈 AtCoder------我认为这是一个非常出色的平台。它最大的优点是立即可用 。是的,你,正在读这篇文章的人,只要你懂一点编程语言,就可以去 AtCoder 网站,选择一个 ABC(AtCoder 初学者比赛),很有机会解决前两个问题,因为这些问题的设计就是让每个人都能解答。如果你解不出来,就去看题解。反复练习(在"如何练习"部分会有更多关于这种方法的内容),每次尽可能多地解决问题,你会很快看到进步。

Once ABCs become too easy, move onto ARCs (AtCoder Regular Contests), and then to AGCs. Of course, just like Codeforces, these contests are hosted by AtCoder - meaning you can compete in them! And just like that, you can rapidly improve at competitive programming without even really realising it, and even enjoying the competitive aspect of it. Note that you can also use Codeforces in a similar way, but I particularly like that AtCoder has very easy problems to allow people with no experience to dive straight into competitive programming.

当 ABC 变得过于简单时,就参加 ARC(AtCoder 常规比赛),然后是 AGC。当然,和 Codeforces 一样,这些比赛也是由 AtCoder 举办的------这意味着你可以参加比赛!就这样,你可以在不知不觉中迅速提高竞技编程水平,甚至还能享受比赛的乐趣。注意,你也可以用类似的方式使用 Codeforces,但我特别喜欢 AtCoder 有非常简单的问题,让没有经验的人可以直接进入竞技编程。

There are many other online judges (websites you can solve problems, submit code, and get instant feedback), such as DMOJ, SPOJ, and Kattis. These sites have a variety of problems and also often allow you to sort problems by difficulty/number of solves, as William demonstrates in his video with Codeforces. You can try them all out, see which problems you like the most perhaps, but I recommend sticking to one when you're starting out. For example, many Japanese competitive programmers have only used AtCoder in their competitive programming journey.

还有许多其他在线评测系统(你可以在这些网站上解决问题、提交代码并获得即时反馈),比如 DMOJ、SPOJ 和 Kattis。这些网站有各种各样的问题,还经常允许你按难度/解决次数对问题进行排序,就像威廉在视频中用 Codeforces 展示的那样。你可以都试试,看看你最喜欢哪些问题,但我建议刚开始时坚持用一个。例如,许多日本竞技程序员在他们的竞技编程过程中只用过 AtCoder。

Study Resources
学习资源

Great - now we know about many platforms that exist for you to solve problems/compete on, and we also have a rough idea of a solid practice routine. However, there is one key aspect of competitive programming that deserves to be explored in more depth: how to learn new concepts. As you improve, you will very quickly come across unfamiliar topics, and it's essential that you tackle that unfamiliarity in a suitable manner - when you come across a DFS problem for the first time, should you buy a book on Graph Theory and spend a month learning it all? Obviously not. I am now going to share some resources for studying (or more accurately, learning) and what you should do in such a situation.

很好------现在我们知道了你可以用来解决问题/比赛的许多平台,我们也大致了解了一个稳固的练习流程。然而,竞技编程有一个关键方面值得深入探讨:如何学习新概念。随着你水平的提高,你会很快遇到陌生的话题,而以合适的方式应对这种陌生感至关重要------当你第一次遇到深度优先搜索(DFS)问题时,你应该去买一本图论的书,花一个月的时间去学习它吗?显然不是。现在,我要分享一些学习(更准确地说是获取知识)的资源,以及在这种情况下你应该怎么做。

There is one learning resource that stands out above the rest, in my opinion. It is the Competitive Programmer's Handbook, by CSES - link. It is completely free, and covers pretty much everything any beginner/intermediate competitive programmer needs to know. It includes implementations and proofs, as well explanations of the intuition behind solutions. I cannot recommend this enough. Take our situation from earlier - when you come across the term DFS, simply look it up in the handbook, read the section, and you're done! (You'll also want to solve some problems on it to test/refine your understanding - more on this later) Another great thing about this resource is that it goes through topics in a good order. So, you can literally just read through it, if you so desire. There are, of course, other great resources to improve your competitive programming knowledge - one of which being, as you might expect, YouTube videos.

在我看来,有一个学习资源是最出色的。它就是 CSES 出版的《竞技程序员手册》------链接。这本书完全免费,涵盖了任何初学者/中级竞技程序员需要知道的几乎所有内容。它包括实现代码和证明,以及对解决方案背后直觉的解释。我极力推荐这本书。回到我们之前的情况------当你遇到深度优先搜索(DFS)这个术语时,只需在手册中查找,阅读相关内容,你就搞定了!(你还会想在它上面解决一些问题来测试/完善你的理解------稍后会详细说)这个资源的另一个优点是,它按很好的顺序讲解主题。所以,如果你愿意,你可以直接从头到尾阅读。当然,还有其他一些很棒的资源可以提升你的竞技编程知识------正如你可能预料到的,YouTube 视频就是其中之一。

Errichto, who I have mentioned already, makes fantastic educational videos. He made an entire series on Dynamic Programming, a fundamental concept, which helped me enormously. SecondThread has also made some great beginner-level content, and I personally enjoy Algorithms Live's videos (but they may be a bit less accessible to newbies).

我之前提到过的Errichto,制作了非常棒的教育视频。他制作了一个关于动态规划(一个基础概念)的完整系列,这对我帮助极大。SecondThread 也制作了一些很棒的初学者内容,我个人很喜欢Algorithms Live 的视频(但对新手来说可能稍显晦涩)。

There's another amazing resource I want to highlight that goes hand-in-hand with the previous paragraph, and that is Codeforces blogs. Codeforces, which is indeed a contest-hosting platform, is also the largest community of competitive programmers in the world. If you come across a topic/technique you want to learn, just add "codeforces" to your Google search, and it's likely several resource list/tutorial blogs will come up.

我还想强调另一个与前一段内容相辅相成的绝佳资源,那就是 Codeforces 博客。Codeforces 确实是一个比赛举办平台,但同时也是世界上最大的竞技程序员社区。如果你遇到一个你想学习的主题/技巧,只需在谷歌搜索中加上"codeforces",很可能就会出现许多资源列表/教程博客。

For example, say I have tried to solve a problem for a while, and gave up. I read the editorial, which mentions using the "Convex Hull Trick for Dynamic Programming ". I think to myself, what on earth is that? Many people of my rating solved this problem, so I should really be able to solve it myself! Let me go learn it! All I have to do is search up "convex hull trick codeforces " in Google - and bam, there are pages of search results with tons of useful material specifically about using this trick in competitive programming (see for yourself!). I can even search up "convex hull trick problems codeforces " - clicking on the very first Codeforces blog that comes up, and scrolling down, I see a whole bunch of previously seen competitive programming problems linked that I can use to practice this very technique . And bear in mind, this specific algorithm is not at all a beginner topic! Imagine if it was an easier topic that I was searching for!

例如,假设我尝试解决一个问题,但最终放弃了。我看了题解,它提到使用"动态规划的凸包技巧 "。我心想,这是什么玩意儿?很多和我水平相当的人都解决了这个问题,我应该也能自己解决!让我去学学!我只需要在谷歌上搜索"convex hull trick codeforces "------砰,出现了好几页搜索结果,全是关于在竞技编程中使用这个技巧的具体 有用材料(你可以自己看看!)。我甚至可以搜索"convex hull trick problems codeforces "------点击第一个出现的 Codeforces 博客,向下滚动,我看到了许多之前见过的竞技编程问题链接,我可以用来练习这个技巧 。请注意,这个特定算法绝对不是初学者话题!想象一下,如果我搜索的是一个更简单的话题!

There's one final resource which I'd briefly like to touch on, that you could say I have a bias for. It's a textbook used in MIT and several other institutions, known as Introduction to Algorithms. Its authors have initials C, L, R and S, and thus is often also called CLRS. Interestingly, it's additionally known as The Bible, which should already indicate how great of a resource it is! I like it because not only does it describe algorithms and provide implementations, but proves correctness and explains the mathematics underlying them. Objectively though, it is massive overkill for competitive programming - it's over a thousand pages long, and if you buy it, like I did, it will set you back quite a bit. The reason I wanted to mention it is that it's a superb resource if you are interested in algorithms/problem solving/math in general, and I can say with confidence that even if I hadn't persisted with competitive programming, it'd still be worth every penny.

最后,我想简单提一下一个资源,你可以说我对它有偏爱。这是一本在麻省理工学院和许多其他机构使用的教科书,叫做《算法导论》。它的作者名字首字母分别是 C、L、R 和 S,因此也常被称为 CLRS。有趣的是,它还被称为《圣经》,这已经表明它是一个多么出色的资源了!我喜欢它,因为它不仅描述了算法并提供了实现方法,还证明了正确性并解释了它们背后的数学原理。然而,客观地说,对于竞技编程来说,它简直是大材小用------它有 1000 多页,如果你买了它,就像我一样,你会花掉不少钱。我想提到它的原因是,如果你对算法/解决问题/数学感兴趣,它是一个极好的资源,我可以肯定地说,即使我没有继续从事竞技编程,这本书也物有所值。

How to Practice/Improve
如何练习/提高

OK, let's now formalise a practice routine, and start to bring everything together. I, and many others, recommend the following - solve problems that are slightly challenging for you (say, ( 0 - 200 ) points above your rating on Codeforces) (using the Practice Resources ). When you are starting out, if you cannot solve a problem within, say, twenty minutes - stop (there's a good chance a technique is required that you are not familiar with). Then, read the editorial, go learn the technique (using the Study Resources ) and solve problems on that technique, if it uses a technique you don't know. If it doesn't, fully digest the editorial, understand the logic behind it, and up-solve the problem . This (in most cases) means to solve a problem you couldn't solve after reading (some or all of) its solution, and is crucial, especially when you are starting out and lack implementation skills.

好的,现在我们来正式制定一个练习流程,并开始整合所有内容。我和许多人都推荐以下方法------解决对你来说有点挑战性的问题(比如,在 Codeforces 上,比你的评分高 (0 - 200) 分的问题)(使用练习资源 )。刚开始时,如果你在二十分钟内解不出一个问题------就停下来(很可能是因为你不知道需要使用哪种技巧)。然后,阅读题解,去学习这种技巧(使用学习资源 ),如果它使用了你不知道的技巧,就解决这类技巧的问题。如果它没有使用你不知道的技巧,就彻底消化题解,理解其背后的逻辑,并重新解决这个问题。在大多数情况下,这意味着在阅读(部分或全部)解决方案后,解决你之前无法解决的问题,这非常重要,尤其是当你刚开始且缺乏实现技能时。

There's another similar technique, that I have heard that even Grandmasters still use - simply pick a problem difficulty (e.g., ( 200 ) points above your current Codeforces rating), filter all problems down to those corresponding to that difficulty, and solve all of them, reading editorials, learning and up-solving where you see fit. Then, compete in contests to get to that rating, and repeat the process. Note however that you should not follow this exact method if you are a beginner, because there will simply be too many problems of a low difficulty for you to solve them all!

还有一个类似的方法,我听说即使是特级大师还在使用------简单地选择一个问题难度(例如,比你目前的 Codeforces 评分高 (200) 分),将所有问题筛选到对应该难度的问题,并解决所有这些问题,阅读题解,根据需要学习并重新解决问题。然后,参加比赛以达到那个评分,并重复这个过程。但请注意,如果你是初学者,你不应该完全按照这种方法去做,因为会有太多低难度的问题,你不可能全部解决它们!

Now, there's one key point here that I've just sort of skimmed over - competition! It is competitive programming, after all. If contests didn't exist, what would be the point? Platforms like Codechef, Codeforces and AtCoder hold contests and have a rating system, which is a HUGE motivator to improve and practice. If you're starting out, for example, set yourself the following challenge - every time you compete in an AtCoder contest, try and do better (get a higher rank) than the last contest. Alternatively, if you have friends that do competitive programming, try and get to a higher rating than them! Or, challenge yourself to get to, say, Expert, or Candidate Master, or even Specialist/Pupil (if you're just starting out) on Codeforces. Simply competing in contests, then up-solving the problems you didn't solve, is yet another excellent practice routine, which often doesn't even feel like practice at all. In fact, as I touched on earlier, because of the accessibility of AtCoder Beginner Contests, you can solely use this practice method with ABCs, which can make the process interesting and enjoyable. Note that virtual participation is a thing - essentially, you can compete in a contest you haven't done before as if you were in the contest itself . It's supported on Codeforces and AtCoder, and probably many more platforms. Thus, if there is no ongoing contest or you don't want to risk losing rating, you can still feel like you're competing.

现在,我刚刚简单提到了一个关键点------比赛!毕竟,这是竞技编程。如果没有比赛,那还有什么意义呢?像 Codechef、Codeforces 和 AtCoder 这样的平台举办比赛,并设有评分系统,这是激励你提高和练习的巨大动力。例如,如果你刚开始,给自己设定以下挑战------每次参加 AtCoder 比赛,都努力比上一次做得更好(获得更高的排名)。或者,如果你有朋友也从事竞技编程,努力获得比他们更高的评分!或者,挑战自己在 Codeforces 上达到,比如说,专家级,或者候选大师级,甚至是专业级/新手级(如果你刚开始的话)。仅仅参加比赛,然后重新解决你没解决的问题,又是另一种极好的练习方法,而且往往根本就不觉得是在练习。事实上,正如我之前提到的,由于 AtCoder 初学者比赛的可及性,你可以只用这种方法来练习 ABC,这可以使整个过程变得有趣且令人愉悦。请注意,虚拟参赛是存在的------本质上,你可以参加一个你之前没参加过的比赛,就像你真的在比赛现场一样。Codeforces 和 AtCoder 支持这种模式,可能还有许多其他平台也支持。因此,如果没有正在进行的比赛,或者你不想冒险失去评分,你仍然可以感受到比赛的氛围。

There's one final practice/improvement resource I'd like to cover that can really deepen your understanding of theory, and allow you to solve more/harder problems. This is the CSES problem set. The astute among you will realise that CSES has already been mentioned - they made the handbook! This problem set goes hand-in-hand with it, actually, and provides practice problems for the topics mentioned in the book! This way, when you read a section of the book, you can solve problems on it, and be better prepared when problems on those topics come up in contests.

最后,我想介绍一个可以加深你对理论的理解并让你解决更多/更难问题的练习/提高资源。这就是CSES 问题集。敏锐的读者会意识到 CSES 已经被提到过了------他们编写了手册!实际上,这个题集与手册相辅相成,为书中提到的主题提供了练习题!这样一来,当你阅读书中的某个章节时,你可以通过解决相关问题来加深理解,当你在比赛中遇到这些主题的问题时,也会更有把握。

An anecdote about improvement and practice:
一个关于进步和练习的小故事:

So far, I've sort of just thrown information and practice methods at you. I'm now going to explain how I overcame a big hurdle that was preventing me from improving, to demonstrate that the methods I've described so far can facilitate your competitive programming journey.

到目前为止,我基本上只是向你抛出了各种信息和练习方法。现在,我要讲讲我是如何克服阻碍我进步的一个重大障碍的,以此来证明我之前描述的这些方法能够助力你的竞技编程之旅。

As I mentioned at the very beginning of this post, I started competitive programming with very little CS/math background knowledge. I started solving problems and gaining rating, which was great. I was really drawn to the more programming-y problems, involving greedy algorithms, DP, graphs, data structures, etc., and so solved a lot of problems on these topics. However, I soon realised something - I was terrible at math problems. Math is very important in competitive programming - specific areas of math, to be more accurate, as William Lin explains in his video. I would constantly come across low-rated (easy) problems that I would really struggle with simply because they were math. This was a huge problem for me, and cost me a lot of rating points. It got to the point where I was able to implement Segment Trees, but did not know about the Triangle Inequality (yes, when I said I had virtually no math background, I was not joking!).

正如我在文章开头提到的,我开始竞技编程时几乎没有计算机科学和数学背景知识。我开始解决问题并提升评分,这很好。我特别喜欢涉及贪心算法、动态规划、图、数据结构等的编程问题,因此解决了很多这类问题。然而,我很快意识到一个问题------我非常不擅长数学问题。数学在竞技编程中非常重要------更准确地说,是特定领域的数学知识,正如威廉·林在他的视频中解释的那样。我总是遇到一些低难度(简单)的问题,却因为它们涉及数学而苦苦挣扎。这对我来说是个大问题,让我损失了很多评分。到了最后,我都能实现线段树了,却不知道三角不等式(是的,我说我的数学基础几乎为零,可不是开玩笑的!)。

So, when I had some free time, I simply did the following - pretty much every day, for nearly two weeks, I would pick a random AtCoder Beginner Contest I hadn't done before (there is a great website that lets you see which AtCoder problems and contests you haven't solved), and force myself to solve until Problem F. Note that I did this because AtCoder is an extremely mathematical programming platform . It is not at all uncommon for an AtCoder problem statement to simply be "Evaluate this function:", followed by some long math expression.

所以,当我有空闲时间时,我简单地做了以下事情------差不多连续两周,我几乎每天都会选择一个我之前没做过的随机 AtCoder 初学者比赛(有一个很棒的网站,可以让你看到你还没解决的 AtCoder 问题和比赛),然后强迫自己做到 F 题。请注意,我这么做是因为AtCoder 是一个极其注重数学的编程平台。AtCoder 的问题陈述中,出现"计算这个函数:"的情况并不罕见,后面跟着一个长长的数学表达式。

While solving the contest's problems, if I couldn't solve a problem after around an hour of thinking (sometimes, I gave myself up to ( 3 ) hours for the Problem Fs), only then would I read the editorial, and even then, I would make sure I understood it, no matter how long it took. If it was a topic, such a combinatorial technique I wasn't familiar with, I would use the Study Resources I've described earlier to learn it, then up-solve the problem after. After doing this for a couple of weeks, I was amazingly no longer terrible at math! Interestingly, now, some of my strongest topics are math-related, something I would have never dreamt of. Even more interestingly, months after doing this "training" (if you can call it that), I saw a Codeforces blog post, where the author, a Grandmaster, explained that he used almost an identical method to improve at math problems!

在解决比赛问题时,如果我在思考了大约一个小时(有时,对于 F 题,我会给自己最多 (3) 个小时)后仍然无法解决,我才会去看题解,而且即使这样,我也会确保自己理解它,不管需要多长时间。如果是一个我不熟悉的主题,比如组合技巧,我会使用我之前描述的学习资源 来学习它,然后再重新解决这个问题。这样做了几周后,我惊讶地发现自己不再那么不擅长数学了!有趣的是,现在,我的一些最强项是与数学相关的,这是我之前从未敢想的。更有趣的是,在进行了这种"训练"(如果可以这样称呼的话)几个月后,我看到了 Codeforces 的一篇博客文章,作者是一位特级大师,他解释说他几乎用了完全相同的方法来提高解决数学问题的能力!

I will now go over some commonly asked questions, and my responses to them.
现在我将回答一些常见问题。

1) Do I need to study DSA beforehand?
1) 我需要先学习数据结构与算法(DSA)吗?

The short answer: no. Solve problems, learn the DSA stuff when you come across a problem that requires it, and then solve problems on that topic (a recurring theme in this post!). This prevents you from spending hours trying to understand a DS/A you are just too inexperienced to understand.

简短回答:不需要。解决问题,在遇到需要数据结构与算法的问题时学习相关内容,然后解决这类问题(这是本文反复强调的主题!)。这样可以避免你花数小时去理解那些你因经验不足而无法理解的数据结构与算法。

Of course, if you are interested in DSA in general, feel free - it won't hurt, of course, and can only help your future self. But, for sure, if you dive right in, you will soon come across a beginner-level DSA concept, such as prefix sums or binary search while solving problems. And so, you will inadvertently be learning DSA at a pace that suits you!

当然,如果你对数据结构与算法本身感兴趣,那也无妨------当然,这不会有害,反而会对未来的你有所帮助。但可以肯定的是,如果你直接开始解决问题,你很快就会遇到一些初级的数据结构与算法概念,比如前缀和或二分查找。这样,你就会在适合自己的节奏下不知不觉地学习数据结构与算法!

2) What programming language to learn?
2) 学习哪种编程语言?

Now, this is a lot more controversial. I don't think there is a right answer. Objectively, C++ is the best. Its standard library, speed, paired with the simple fact that most competitive programmers use it, makes it unparalleled. But is it worth going out of your way to learn a new language just for competitive programming? Or is it worth learning such a hard language from scratch? Honestly, it's up to you. If you're just starting out, you can just use the language you know best. Often, competitive programmers start with Java or Python, and later switch to C++. So, the choice you make now isn't all too important.

这个问题更具争议性。我认为没有绝对正确的答案。客观地说,C++ 是最好的。它的标准库、速度,加上大多数竞技程序员都使用它的事实,使其无与伦比。但为了竞技编程而特意去学习一种新的语言值得吗?或者从头开始学习这么难的语言值得吗?说实话,这取决于你。如果你刚开始,你可以直接使用你最熟悉的语言。通常,竞技程序员会从 Java 或 Python 开始,然后转向 C++。所以,你现在做的选择并不是那么重要。

Do your research on your language of choice - if it is semi-popular (e.g. Java, Python), think well before going out of your way to learn a new one (although, as mentioned earlier, you don't need that much C++ for competitive programming). If you don't know any language, I'd say go with C++ - you can be confident it will serve you well and you won't have to ever switch in the future. But, those are just my two cents - there are probably hundreds of blogs/videos about this question, maybe check out others' POV before making a decision on what language to learn.

对你要选择的语言进行研究------如果它是一种半流行的编程语言(比如 Java、Python),在特意去学习一种新的语言之前,要好好考虑一下(尽管如前面提到的,竞技编程并不需要太多的 C++ 知识)。如果你还不懂任何编程语言,我会说选择 C++------你可以放心,它会为你服务得很好,而且你以后也不用再换语言了。但这些只是我的个人看法------关于这个问题可能有成百上千的博客和视频,也许在决定学习哪种语言之前,你可以看看其他人的观点。

As a final note, Python is often considered far worse than C++ and Java for competitive programming, but a Python programmer has recently become a LGM on Codeforces. Probably though, choose a language from these three (they are by far the most popular), but which one you choose among them is not nearly as important as your ability to solve problems - I think everyone will agree with me on that.

最后,虽然 Python 通常被认为在竞技编程中远不如 C++ 和 Java,但最近有一位 Python 程序员 在 Codeforces 上成为了传奇大师。不过,大概率你会从这三种语言中选择一种(它们是最受欢迎的),但你选择哪一种,远没有你解决问题的能力重要------我想每个人都会同意我的观点。

conqueror_of_tourist - Codeforces
https://codeforces.com/profile/conqueror_of_tourist

3) (I've decided to learn / I'm considering learning) C++, but I don't know anything right now. How should I learn it?
3) (我决定学习/我在考虑学习)C++,但我现在一无所知。我该如何学习它呢?

This is an extremely pertinent question, that I think I am capable of answering well given that I knew no programming (let alone C++) before doing competitive programming.

这是一个非常相关的问题,鉴于我在开始竞技编程之前对编程(更不用说 C++ 了)一无所知,我认为我能够很好地回答它。

My main response may seem counter-intuitive: DO NOT BUY A C++ BOOK/COURSE . The C++ that is required for competitive programming is a very specific subset of the language itself. For example, not once have I EVER had to even think about memory management in competitive programming . Also, not once have I EVER had to use inheritance or similar OOP concepts in competitive programming . All C++ programmers appreciate how crucial memory management and OOP is to the language, and for sure, any good book or course you take will go into those two aspects, most likely in some depth. This will be almost completely useless to you in competitive programming - it's simply not worth your money. To give yet another example, I was watching a live-stream by a top competitive programmer who mentioned that they do not understand pointers and references in C++ . So, you don't even need to understand what a pointer is for competitive programming, but it is imperative that you have a deep understanding of the algorithmic parts of the STL? Good luck finding a course/book that follows such a layout!

我的主要回答可能看起来有些反直觉:不要去买 C++ 的书或课程 。竞技编程中需要的 C++ 只是这门语言的一个非常特定的子集 。例如,我在竞技编程中从未 想过内存管理的问题。同样,我也从未 在竞技编程中使用过继承或类似的面向对象编程概念。所有 C++ 程序员都知道,内存管理和面向对象编程对这门语言来说有多重要,当然,你参加的任何一本好书或课程都会 深入讲解这两个方面。但在竞技编程中,这些对你来说几乎完全没用 ------根本不值得你花钱。再举个例子,我曾观看一位顶级竞技程序员的直播,他提到自己不理解 C++ 中的指针和引用。所以,在竞技编程中,你甚至不需要理解指针是什么,但你必须深入理解标准模板库(STL)的算法部分?祝你好运,能找到一本遵循这种布局的课程或书籍!

Of course, you can pick and choose the parts that you think are relevant, but I instead recommend a different way of learning the language, and this is what I did. First off, learn the basics. Learn how functions work, variables, types, etc. In fact, most of you reading this post will already know all of this. But if you don't, (and even if you do, just to be sure) find a YouTube video/beginner-level course that explains the absolute basics. I am not going to go in any more depth on how to learn basic C++, as I am sure there are hundreds of resources on this topic.

当然,你可以挑选你认为相关的内容来学习,但我建议采用一种不同的学习语言的方法,这也是我所做的。首先,学习基础知识。学习函数的工作原理、变量、类型等。实际上,阅读这篇文章的大多数人可能已经知道这些了。但如果你不知道,(即使你知道,也为了确保万无一失)找一个 YouTube 视频或初级课程来了解基础知识。我不再深入讲解如何学习基础 C++,因为我相信关于这个主题的资源数不胜数。

Once you know some of the basics, I'd say also read some of the handbook (as you've probably realised, I'm a huge fan of this resource), which will also teach you some essential features of the language required for competitive programming (STL, overflow, etc). During this time, you can also start solving problems. As you solve problems, make sure to look at the top competitors' code/editorial code , as doing so will gradually expose you to the C++ features required for competitive programming. For example, you may look at the top seed's code on a sorting problem and see how they sorted a std::vector based on a custom comparator, how they used std::priority_queue to implement Dijkstra's Algorithm, or that they a built-in function, "std::lower_bound", to arrive at a simple solution. If you don't understand a specific function or container, for example, Google it and/or look at the reference docs. Once again, we see the common theme of learning a certain aspect as of when you need it, which I am a big advocate for as it prevents you from learning useless information. (Of course, if you are interested in learning C++ in general, do indeed buy a book/course and learn stuff you want to learn about - in this response, I am primarily addressing those who want to learn C++ solely to use for competitive programming.)

一旦你掌握了一些基础知识,我建议你也可以阅读一些手册(正如你可能已经意识到的,我非常推崇这个资源),它还会教你一些竞技编程所需的语言的基本功能(标准模板库、溢出等)。在这期间,你也可以开始解决问题。在解决问题时,一定要查看顶级选手的代码/题解代码,因为这样做会逐渐让你接触到竞技编程所需的 C++ 特性。例如,你可能会查看一个排序问题的顶级选手的代码,看看他们是如何根据自定义比较器对 std::vector 进行排序的,他们是如何使用 std::priority_queue 来实现迪杰斯特拉算法的,或者他们是如何使用内置函数"std::lower_bound"来得出一个简单解决方案的。如果你不理解某个特定的函数或容器,例如,可以在谷歌上搜索,或者查看参考文档。再次强调,我们看到的共同主题是,在你需要的时候学习某个方面的知识,我非常推崇这一点,因为它可以防止你学习无用的信息。(当然,如果你对学习 C++ 本身感兴趣,确实应该购买书籍或课程,学习你感兴趣的内容------在这个回答中,我主要针对那些只想学习 C++ 用于竞技编程的人。)

If you are struggling with writing C++ or implementation, it goes without saying that you should practice writing C++ and implementation! I found it helpful to pick some easy competitive programming problems, and try to solve them as quickly as I could. This definitely improved my command of the language and my ability to implement solutions quickly, both of which are essential to competitive programming.

如果你在编写 C++ 或实现代码方面有困难,不用说,你应该多练习编写 C++ 和实现代码!我发现选择一些简单的竞技编程问题,然后尽可能快地解决它们,这对我很有帮助。这确实提高了我对语言的掌握程度和快速实现解决方案的能力,而这两者对于竞技编程来说都是非常重要的。

Final Notes
最后的说明

Firstly, I'd like to quickly give a shout-out to this post, which inspired me to write this one.

首先,我想快速提一下这篇文章,它启发我写了这篇文章。

Guide: How to actually get good at leetcode : r/csMajors
https://www.reddit.com/r/csMajors/comments/yvgor9/guide_how_to_actually_get_good_at_leetcode/

Secondly, please note that there are several posts just like this one which you find useful. You can find ones written by top competitive programmers, such as this one, this one, or this one, and also ones written by more "average" competitive programmers, on Codeforces. It may be that you share a more similar background with others than you do with me, and so learning about their journeys and practice routines might be more useful.

其次,请注意,还有许多像这样的帖子对你来说可能很有用。你可以找到由顶级竞技程序员撰写的,比如这一篇这一篇这一篇,也可以找到在 Codeforces 上由更"普通"的竞技程序员撰写的。也许你和其他人的背景比我更相似,所以了解他们的经历和练习方法可能会更有帮助。

Thirdly, there was actually another question that I had planned to answer, "Why should I even do/persist with competitive programming?", but this post is already long enough as it is. If anyone is interested, I can certainly write another post with my thoughts on this question.

第三,我原本还计划回答另一个问题:"我为什么要从事/坚持竞技编程?"但这篇文章已经够长了。如果有人感兴趣,我当然可以再写一篇文章,谈谈我对这个问题的看法。

One final thing - please leave any questions/comments you may have on this post, instead of PM-ing me about it ! That way, others will also be able to see/respond.

最后一件事------请在本文中留下你可能有的任何问题/评论,而不是私下联系我!这样,其他人也能看到并回复。

If you've made it this far, thank you for reading! I realise this post is extremely unorganised; I apologise for this, and for any grammatical errors I have undoubtedly made. Hopefully, you were still able to take away something of value.

如果你读到这里,感谢你的阅读!我意识到这篇文章非常杂乱无章;我为此道歉,也对我肯定犯下的语法错误表示歉意。希望你仍然能从中得到一些有价值的东西 。


Guide: How to actually get good at leetcode

指南:如何真正提升力扣刷题能力

r/csMajors • 3 years ago

So I've seen a lot of posts recently asking how to get good at leetcode. I see countless posts from beginners who don't know how to start and panic at not being able to solve easies despite taking a ds&a course. I see posts from those who have done 200+ questions but still can't reliably solve mediums on their own. As someone who recently went through the journey of going from zero DS&A knowledge to interview-ready in 4 months. I figured I'd write a step-by-step guide of what I did to help everyone out. This post is not intended to be a philosophical discussion on whether leetcode is appropriate for interviews, this will be an actionable guide with concrete steps that you can follow.

最近我看到很多帖子都在询问如何提升力扣刷题能力。我见过无数初学者发帖求助,他们虽然修读过数据结构与算法(DS&A)课程,却不知从何入手,甚至会因为连简单题都无法解决而感到慌张。我也见过一些刷了 200 多道题的人,依然无法稳定独立解决中等难度的题目。作为一名在 4 个月内从零基础掌握数据结构与算法、达到面试水平的过来人,我决定写下这份详细的分步指南,分享自己的经验来帮助大家。本文不打算对力扣是否适合作为面试考核工具展开哲学层面的讨论,而是提供一份具备可操作性、步骤明确的行动指南。

Who am I and why you should listen to me:
关于我,以及你为何可以参考我的经验:

I have to preface this guide with my background so you can trust that I know what I'm talking about. I'm a recent mechanical engineering graduate from a Canadian university who self-studied computer science and web development and landed a software engineer role. Part of this self-study process involved learning DS&A and leetcode which took 4 months by studying 3-4 hours a day, 6 days a week. At the start of my journey, I couldn't even solve easies. After these 4 months, I'm now able to consistently (90% of problems) solve mediums in ~20 minutes and hards in ~35 minutes on my own. I also usually solve OAs (tiktok, SIG, IMC, blackrock, pure storage, c3 ai, cisco, tower research) with 100% test cases, and scored 822 on my one codesignal gca attempt (not the best, ran out of time debugging q3 lol). I've done 6 leetcode questions during onsite interviews and have optimally solved all of them. I'm not trying to flex, just trying to show that what I'm saying is credible.

在介绍这份指南之前,我需要先说明自己的背景,以便让大家相信我所分享内容的可靠性。我毕业于加拿大一所大学的机械工程专业,通过自学计算机科学与网页开发,成功拿到了软件工程师的职位。自学过程中,数据结构与算法和力扣刷题的学习阶段耗时 4 个月,我保持每周 6 天、每天 3-4 小时的学习节奏。学习初期,我甚至连简单题都无法解决。经过这 4 个月的积累,我现在能够稳定地独立解题------90% 的中等难度题目可以在约 20 分钟内完成,困难难度题目则约 35 分钟。我在多家公司的在线测评(OA)中,均能 100% 通过测试用例,涉及企业包括 TikTok、SIG、IMC、贝莱德(BlackRock)、Pure Storage、C3 AI、思科(Cisco)、Tower Research 等。我参加过一次 CodeSignal GCA 测评,取得了 822 分的成绩(不算顶尖,第三题调试时用完了时间,哈哈)。在现场面试中,我完成了 6 道力扣题目,且全部给出了最优解。我并非在炫耀,只是想证明我所分享的方法是切实有效的。

My overall strategy:
我的整体学习策略:

As a preface, the goal of this guide is to deeply understand the techniques needed to solve LC problems at an abstract level and implement your abstract solution quickly. My approach is based off how technical material is taught in university courses. What they do is teach a strategy/technique at an abstract level, walk through solving guided example problems using that strategy, have students practice through assignments and practice finals, then apply what you've learned on the actual exams. My overall approach to learning is breadth -> depth -> breadth. First learning what you'll be learning (breadth), learning those specific topics with a full and deep understanding (depth), then tying the specific topics back into the big picture and how they relate to each other (breadth). I also write summary notes after I read through a topic, I find this lets me take all the information and form a generalized abstraction of the topic along with critical specifics, and if I'm able to write a page of well-structured notes using my own understanding of what I just learned then that means I understand the topic deeply. I also re-read these notes at the end of each of the 4 steps for spaced-repetition effects or when I need to jog my memory since re-reading my own written notes takes me back to the mental state I was in when I first wrote them.

首先需要明确,这份指南的目标是让读者在抽象层面深入理解解决力扣题目所需的各类技巧,并能够快速将抽象解法转化为实际代码。我的学习方法借鉴了大学专业课程的授课模式:先从抽象层面讲解一种策略或技巧,再通过例题演示如何运用该策略解题,接着让学生通过作业和模拟测试进行练习,最后在正式考试中检验所学知识。我的整体学习路径遵循 广度→深度→广度 的顺序:第一步,了解将要学习的内容范围(广度);第二步,对每个具体知识点进行全面且深入的钻研(深度);第三步,将各个知识点回归到知识体系的全貌中,梳理它们之间的关联(广度)。此外,我在学完每个知识点后都会撰写总结笔记,我发现这种方式能帮助我整合所有信息,提炼出该知识点的通用抽象模型以及关键细节。如果我能凭借自己的理解,写出一页结构清晰的笔记,就说明我已经深入掌握了这个知识点。在四个学习步骤的每一步结束后,我都会重新阅读这些笔记,利用间隔重复的原理巩固记忆;或者在需要唤醒记忆时翻阅笔记,因为重读自己的笔记能让我回想起初次学习时的思维状态。

Step 1: Learn Python (or Java or C++):
步骤 1:学习 Python(或 Java、C++)

The first step is to get familiar with your programming language of choice. I chose Python and recommend you do the same if you have time, but if you're in a rush then just use whatever you're familiar with as long as it's acceptable in coding interviews (Python, Java, C++). Python is the least verbose language and most similar to plain pseudo code, and in a timed test every minute counts. It lets you spend less time on implementation and more time on figuring out the abstract algorithm which is where the bottleneck is for coding interviews. You need to be familiar with a language before you can learn DS&A so you can concurrently learn the language implementations of data structures and algorithms. To learn Python I just went through the W3 Schools' guide on syntax and overall language specs (dynamic typing, garbage collection, etc.). The official docs are good as well but they have a lot of stuff that you don't need for coding interviews. I also took notes on the syntax (6 pages). This step took me 10 hours split across 3 days.

第一步是熟练掌握你选定的编程语言。我选择了 Python,如果你时间充裕,我建议你也选择它;但如果时间紧张,使用任何你熟悉且适用于编程面试的语言即可(Python、Java、C++ 均可)。Python 语法最为简洁,最接近自然的伪代码,而在限时测试中,每一分钟都至关重要。使用 Python 可以让你在代码实现上花费更少时间,将更多精力投入到抽象算法的构思中------这正是编程面试的关键难点。在学习数据结构与算法之前,你必须先熟悉一门编程语言,这样才能同步学习数据结构与算法在该语言中的具体实现方式。我通过 W3 Schools 的教程学习 Python 的语法和语言特性(动态类型、垃圾回收等)。Python 官方文档虽然内容详实,但包含了许多编程面试中用不到的内容。我还整理了 6 页的语法笔记。这一步骤我总共耗时 10 小时,分 3 天完成。

Step 2: Learn DS&A:
步骤 2:学习数据结构与算法(DS&A)

With DS&A you need to learn how each data structure and algorithm works deeply at an abstract level. For me this meant visualizing a gif of the algorithm in my head, learning the time space complexities of operations the DS/A supports and why they are what they are, learning how the DS/A handles edge cases, and writing an implementation in Python. The resource I used was the interactive ebook PythonDS3 by Runestone Academy. It's full of word explanations, diagrams, and live code in an editor that you can play around with. It first explains each DS/A at an abstract level, then shows you the Python implementation. I would go through a page/sub-section, think about the concepts deeply and piece everything together in my head, then write a page of notes on that topic. As a preface, I used Tech Interview Handbook's study plan to figure out which topics are important and I need to take notes on, and which are not which I would only read. I also used Tech Interview Handbook's topic-by-topic cheatsheet to confirm time and space complexities and how the DS/A is used in problems. This step took me 6 weeks, and I tried to finish 1 subsection per day. Each subsection only takes 30 minutes to read, but I would reread, think deeply about what I read, google stuff I didn't understand, sometimes watch a youtube video if I still didn't understand it fully, and write my summary notes which all took about 3 hours per subsection.

学习数据结构与算法时,你需要从抽象层面深入理解每一种数据结构和算法的工作原理。对我而言,这意味着在脑海中动态模拟算法的执行过程,掌握该数据结构或算法支持的各项操作的时间复杂度与空间复杂度及其背后的原因,了解它处理边界情况的方式,并使用 Python 实现该数据结构或算法。我使用的学习资源是 Runestone Academy 出品的交互式电子书《PythonDS3》。这本书包含详细的文字解释、图表,以及可在线编辑运行的代码案例。它的讲解逻辑是先从抽象层面介绍数据结构或算法,再给出对应的 Python 实现代码。我的学习方式是:学完一个页面或子章节后,深入思考其中的概念,在脑海中构建完整的知识框架,然后针对该主题撰写一页总结笔记。需要说明的是,我参考了《技术面试手册》(Tech Interview Handbook)的学习计划,以此区分需要重点学习并整理笔记的内容,以及只需泛读了解的内容。同时,我也借助该手册按主题分类的速查表,来确认各类数据结构与算法的时间复杂度、空间复杂度,以及它们在题目中的应用方式。这一步骤耗时 6 周,我计划每天完成一个子章节的学习。每个子章节的阅读时间仅需 30 分钟,但我会反复阅读、深入思考,遇到不懂的内容就通过谷歌搜索,若仍无法完全理解,还会观看相关的 YouTube 视频,最后整理总结笔记------整个过程每个子章节约耗时 3 小时。

Step 3: Learn Leetcode techniques/strategies (patterns):
步骤 3:学习力扣解题技巧与策略(解题模式)

So here is the most important step that I see a lot of people get wrong. People tend to jump straight into practicing leetcode problems and end up having to do 300+ problems to get interview-ready. The issue with this is that LC problems are designed with particular established strategy in mind, and if you're trying to learn the strategy from particular problems then that's very inefficient. This would be like in calculus, trying to learn the chain rule, fundamental theorem, monotonic convergence by jumping into doing calculus practice finals, or in linear algebra, trying to learn matrix operations, finding eigenvalues, or SVD decomposition by jumping into doing linear algebra finals. You can clearly see how inefficient this approach is. Furthermore, many of these strategies came from breakthrough papers in computer science that took PhDs to come up with and have many pages of rigorous proof. Trying to come up with these strategies from scratch or induction from LC problems would require you to be a genius. Now you see why so many people get stuck at this step, they're doing it completely wrong. The resource I used for this is Grokking the Coding Interview and Grokking Dynamic Programming by Design Gurus and Educative.io (no affiliations). These courses are paid but the information is truly worth the money, as it's by far the best resource I've found for this step and the time and energy you'll save compared to using other resources is well-worth it. If you really can't afford it then I've heard good things about Leetcode Explore cards. There's also a Hackernoon article on coding interview patterns that summarizes the patterns taught in Grokking, but they're pretty succinct and don't offer the depth of information that I think you need. You could pair that with the CSES Competitive Programmer's Handbook to pick out and learn the specific strategies covered by Grokking. I basically used this the same way as with DS&A. For each pattern, I read the primer, read the solutions to the first few problems, tried to solve a few of the later problems in my head abstractly (5-10 minutes of thinking) using the strategy taught in the first few problems, then read the remaining problems (each pattern has 5-14 example problems). Once I finished a pattern, I would piece together the information into an abstract strategy, the situations in which that strategy can be used, what makes the strategy more/less efficient compared to other options, common characteristics in problems where I should consider this strategy, along with its edge cases and time/space complexity, and write down my page of notes. This is probably the most difficult step of the whole plan as you'll be flexing your brain for abstract thinking and logical reasoning. It'll likely be very difficult to think that hard but you'll develop a very strong foundation for solving LC problems later so it's well-worth the mental pain. I would try to aim for fully learning 1 strategy per day which took anywhere from 3-5 hours and there's around 24 strategies total (Grokking the Coding Interview + Grokking Dynamic Programming). For dynamic programming, there's a section in Grokking the Coding Interview but I found it confusing and it only contains 1 DP strategy, so I recommend skipping that one and once you're done GTCI start Grokking Dynamic Programming which explains that strategy better and also has 5 more strategies.

这一步是很多人容易出错的关键环节。很多人倾向于直接开始刷力扣题目,最终往往需要刷 300 多道题才能达到面试水平。问题在于,每一道力扣题目都是基于特定的成熟解题策略设计的,如果试图通过零散的题目来学习这些策略,效率会非常低下。这就好比在微积分学习中,不先学习链式法则、基本定理、单调收敛等理论,直接去做模拟试题;或者在线性代数学习中,跳过矩阵运算、特征值求解、奇异值分解(SVD)的理论学习,直接刷模拟题------这种学习方式的低效性显而易见。此外,许多解题策略源自计算机科学领域的突破性论文,是由博士团队耗费大量精力提出的,并且包含数十页的严谨证明。如果试图从零开始推导这些策略,或者仅通过刷力扣题目归纳总结,需要具备天才般的能力。这就是为什么很多人会在这一步陷入瓶颈------他们的学习方法从根本上就是错误的。我使用的学习资源是 Educative.io 平台上 Design Gurus 出品的《吃透编程面试》(Grokking the Coding Interview)和《吃透动态规划》(Grokking Dynamic Programming)两门课程(我与这些平台和课程无任何关联)。这些课程需要付费,但内容物超所值,是我在这一阶段找到的最优资源,相比使用其他资源,它能为你节省大量时间和精力。如果确实无法承担费用,我听说力扣的探索卡片(Leetcode Explore cards)也很不错。此外,Hackernoon 网站上有一篇关于编程面试解题模式的文章,总结了《吃透编程面试》课程中的核心模式,但内容较为简略,缺乏我认为必要的深度。你可以将这篇文章与《CSES 竞赛程序员手册》(CSES Competitive Programmer's Handbook)结合使用,从中筛选并学习《吃透编程面试》所涵盖的具体策略。我采用了与学习数据结构与算法相同的方法:针对每一种解题模式,先阅读入门介绍,再研读前几道例题的解析,接着尝试在脑海中运用前面例题学到的策略,抽象地推导后续几道题的解法(思考时间控制在 5-10 分钟),最后阅读剩余例题的解析(每种模式配套 5-14 道例题)。学完一种解题模式后,我会整合所有信息,提炼出该模式的抽象策略框架、适用场景、与其他策略相比的效率优劣、适用该策略的题目所具备的共同特征,以及该策略的边界情况和时间/空间复杂度,然后整理成一页笔记。这可能是整个学习计划中难度最高的步骤,因为它需要你充分调动抽象思维和逻辑推理能力。高强度的思考过程可能会让你感到疲惫,但这会为你后续的力扣刷题打下坚实的基础,这份脑力付出是完全值得的。我的目标是每天熟练掌握一种解题策略,每种策略的学习耗时 3-5 小时,两门课程总共涵盖约 24 种策略。关于动态规划部分,《吃透编程面试》中虽然有相关章节,但我觉得讲解较为晦涩,且只包含一种动态规划策略。因此我建议跳过该章节,在学完《吃透编程面试》后,直接学习《吃透动态规划》------这门课程对该策略的讲解更为清晰,并且额外涵盖了 5 种动态规划相关策略。

Step 4: Practice
步骤 4:实战练习

At this step, you should know your Python syntax, understand DS&A, understand the ins and outs of each strategy and should be able to come up with the solution in your head to most LC easy's in 5 minutes and mediums in 10 minutes. The point of this stage is to actually practice the full problem from prompt to code and practice talking out loud (or whisper if you need to be quiet) like you would in an interview. The resource I recommend is Grind 75 grouped by weeks with 70-100 questions total. Go through each question and try to solve it on leetcode. Don't look at the solution until you're stuck for 30 minutes, meaning you haven't made any progress in your logic for 30 minutes, making logical reasoning steps in your head doesn't count as being stuck. To actually solve a problem, read the prompt, visuals, examples, and input ranges. Start with a brute force and solve how you would do it intuitively, typically this means start on element 0 and perform steps until you reach a solution. Then make logical deductions based on what you've been given in the prompt and how your brute force looks (careful, the brute force might be a red herring to the actual optimized solution). Use your logical deductions and match onto a few potential strategies that you think have a high chance of working and investigate how each of those strategies could be used to solve the problem. Sometimes you'll need to combine strategies in series or parallel. If you can't identify any, just try each of the 24 strategies one by one in your head, even if this fails it's all good practice for your logical reasoning skills. You can think of the problem solving process as a graph traversal, where you have your starting state as one node and your goal state as another node. You can add strategies as edges onto your starting node to transform the starting state into a new state. Check if the new state is your goal, if not then add another strategy either onto your new state or your original state and repeat until you reach the goal. Once you have the optimal solution in your head, write down your algorithm in comments above the function in 2-4 lines along with the time and space complexity. Writing the algorithm down takes me a minute, but it saves me 5-10 minutes during my implementation as it lets me focus purely on implementing my algorithm into code by referring to the text when I get confused without having to think "what was my algorithm doing at this step again?". Initially, you'll probably be slow at implementing the algorithm in code and run into a bunch of Python syntax errors. I've spent hours debugging my code in single questions at the start, it's normal and just use this to learn the quirks of Python. After implementing, I check over my code once for silly mistakes and then run through it with one of the example test cases line-by-line, keeping all the variables in my head (use comments if needed). Then I submit and fix my code if the submission failed. Once the submission passes I go look at the solution (either official or in the comments), try to find "easy-to-understand" and ignore the one liners. If I still don't understand the algorithm I'll watch the Neetcode video for it then try to implement it. After around 20 easy's I started solving them (getting the first optimized code solution which may have syntax bugs) in 15 minutes. After the first 20 mediums I started solving them in 30 minutes. Hards are usually a combination of strategies and some (mostly greedy algorithms) you just need to memorize but there aren't too many and so I can usually solve them in 40 minutes right from my first hard unless I just don't know the trick. I did 2-4 problems a day (2-5 hours daily) until I hit 50 problems and that was when I felt confident I could solve 80% of the problems on my own in a reasonable time and the remaining problems if I was given a hint or two which is more than interview-ready.

到了这一阶段,你应该已经熟练掌握 Python 语法,理解数据结构与算法的核心知识,吃透每种解题策略的细节,并且能够在 5 分钟内构思出大部分力扣简单题的解法,10 分钟内构思出中等题的解法。本阶段的核心目标是完整练习从题目要求到代码实现的全流程,同时练习像面试时那样大声阐述解题思路(如果需要保持安静,小声说出即可)。我推荐的练习资源是 Grind 75 题库,该题库按周划分,总共包含 70-100 道题目。逐一完成这些题目,在力扣平台上尝试解题。在连续 30 分钟没有任何思路进展之前,不要查看题解------这里的"没有进展"指的是逻辑推导完全停滞,脑海中的思考推演过程不属于停滞状态。解题的具体步骤如下:首先阅读题目描述、配图、示例和输入范围;接着先构思暴力解法,按照直觉推导解题步骤,通常是从第 0 个元素开始,逐步执行操作直至得到答案;然后根据题目给出的条件和暴力解法的特点进行逻辑推导(需要注意,暴力解法可能会误导你偏离最优解的方向);利用推导结果,匹配几种你认为可行的解题策略,分析每种策略在本题中的应用方式------有时需要将多种策略串联或并联使用;如果无法匹配到合适的策略,可以在脑海中逐一尝试 24 种策略,即便尝试失败,这也是对逻辑推理能力的有效锻炼。你可以将解题过程想象成图的遍历:把初始状态视为一个节点,目标状态视为另一个节点,将解题策略视为连接节点的边,应用策略可以将初始状态转化为新的状态;检查新状态是否为目标状态,若不是,则在新状态或初始状态上继续应用其他策略,重复此过程直至达到目标状态。当你在脑海中确定最优解后,在函数上方用 2-4 行注释写下算法思路,同时标注时间复杂度和空间复杂度。写下算法思路仅需 1 分钟,但在代码实现阶段能为你节省 5-10 分钟------这样你可以专注于将算法转化为代码,遇到困惑时只需参考注释,无需反复回想"这一步算法要做什么"。初期阶段,你的代码实现速度可能较慢,还会频繁遇到 Python 语法错误。我在刚开始练习时,曾在一道题上花费数小时调试代码,这是很正常的现象,你可以借此机会熟悉 Python 的语法特性。完成代码实现后,先检查一遍代码,排除低级错误,再选取一个示例测试用例,逐行手动推演代码执行过程,在脑海中记录所有变量的变化(必要时可以添加注释辅助);之后提交代码,如果提交失败则根据错误信息修正代码。提交通过后,查看题解(官方题解或评论区的优质题解),优先选择"易于理解"的解析,忽略那些过于简洁的一行代码解法。如果仍然无法理解题解中的算法,可以观看 Neetcode 上对应的讲解视频,然后尝试自己实现该算法。在完成约 20 道简单题后,我开始能够在 15 分钟内写出简单题的最优解代码(可能存在少量语法错误);完成前 20 道中等题后,解题时间稳定在 30 分钟以内。困难题通常需要多种策略的组合运用,部分题目(多为贪心算法类)需要记忆特定技巧,但这类题目数量不多------因此除非遇到完全不了解的解题技巧,我从第一道困难题开始,就能在 40 分钟内完成解题。我保持每天 2-4 道题的练习量(每日耗时 2-5 小时),当完成 50 道题时,我已经有信心在合理时间内独立解决 80% 的题目,剩余题目只需 1-2 个提示就能解决------这个水平已经远超面试的基本要求。

Bonus step: Maintain your skills:
额外步骤:保持解题能力

Given how common switching jobs is in SWE due to either increasing TC or layoffs/pip/firing, and how interviews in SWE are bottlenecked by LC problems, it makes sense to try to retain your knowledge such that you only need a week or two to prep the next time you interview. I'm planning on doing 1-2 LC problems per week on Sundays which I feel like after all this prep to build a strong foundation and deeply understand the material should be enough to retain my knowledge. My solving speed will probably drop, but I estimate next time I prep I'll only need to review my notes and do 30 LC questions to get me interview-ready. This will probably only take 2 weeks time instead of months. 1-2 questions per week will only take 1-2 hours per week which is nothing for the reward you get by staying near interview-ready. I'll have to try it out to see if this is enough, but it seems like it should be.

在软件工程师行业,无论是为了提高总薪酬(TC)而跳槽,还是因裁员、绩效改进计划(PIP)或解雇而重新求职,跳槽都十分常见;同时,软件工程师的面试中,力扣题目是重要的考核环节。因此,保持已掌握的解题知识非常有必要------这样下次面试时,你只需 1-2 周的时间就能完成备考。我的计划是每周日做 1-2 道力扣题目,在打下坚实基础、深入理解知识的前提下,这种练习频率足以帮助我维持解题能力。我的解题速度可能会有所下降,但我估计下次备考时,只需复习笔记并完成 30 道力扣题目,就能重新达到面试水平,整个过程仅需 2 周,而非数月。每周 1-2 道题的练习量仅需耗时 1-2 小时,与保持接近面试水平所带来的回报相比,这点付出微不足道。我还需要实际验证这种方法是否足够有效,但从目前来看,这个方案是可行的。

And that's the end. If you made it this far, try implementing these steps and let me know how it goes. I hope you find similar success that I have found following these steps. Happy learning!

以上就是这份指南的全部内容。如果你能读到这里,不妨尝试按照这些步骤进行学习,并告诉我你的进展。希望你能通过这些方法,取得和我一样的学习效果。祝你学习顺利!


Competitive Programming - A Complete Guide

竞技编程 ------ 完整指南

Last Updated : 22 Aug, 2025

Competitive Programming is a mental sport that enables you to code a given problem under provided constraints. The purpose of this article is to guide every individual possessing a desire to excel in this sport. This article provides a detailed syllabus for Competitive Programming designed by industry experts to boost the preparation of the readers.
竞技编程是一项智力运动,使你能够在给定的约束条件下编写特定问题的代码。本文的目的是指导每一个有志于在这一领域取得优异成绩的人。本文提供了一份由行业专家设计的竞技编程详细教学大纲,以帮助读者更好地准备。

Why To Do Competitive Programming?

为什么要做竞技编程?

Here are some reasons about why you should start Competitive Programming:

以下是一些你应该开始竞技编程的原因:

  • Mental Agility and Quick Thinking: By practicing competitive programming, you start thinking quickly and within the given timeframe and this improves your mental agility and helps enhance your thinking ability.
    思维敏捷与快速思考: 通过练习竞技编程,你能够在给定的时间内快速思考,这可以提高你的思维敏捷性,并帮助提升你的思维能力。

  • Career Prospect: Competitive programming is very important when it comes to technical interviews for software engineering-related jobs. Many tech giants use competitive programming contests as a medium of recruitment. Companies like Google , ServiceNow , Atlassian , etc. have technical interviews based on competitive programming problems.
    职业前景: 在软件工程相关工作的技术面试中,竞技编程非常重要。许多科技巨头将竞技编程比赛作为招聘的手段。像 谷歌ServiceNowAtlassian 等公司,其技术面试都基于竞技编程问题。

  • Learning Opportunity: In Competitive programming, we get a wide range of variety of problems and various arithmetic concepts . Competitive programming exposes various data structures and algorithms which help us better understand the complexity of problems.
    学习机会: 在竞技编程中,我们会接触到各种各样的问题和 多种算术概念。竞技编程会涉及各种数据结构和算法,帮助我们更好地理解问题的复杂性。

Basics of Competitive Programming:

竞技编程基础:

Basics Of Array , String, Greedy and Bit Manipulation

数组、字符串、贪心算法和位运算基础

Number Theory and Combinatorics

数论与组合数学

Searching, Sorting and Basic Data Structures

搜索、排序和基础数据结构

Tree and Graphs

树和图

Recursion and Dynamic Programming

递归和动态规划

String Algorithms

字符串算法

Geometry and Game Theory

几何和博弈论

Advance Data Structures

高级数据结构

You may also check Geeksforgeeks Online Courses to Learn Data Structures and Algorithms, well designed courses taught by Industry Experts.

你还可以查看 Geeksforgeeks 在线课程,学习由行业专家讲授的精心设计的数据结构和算法课程。


via:

相关推荐
一个平凡而乐于分享的小比特1 个月前
硬链接(ln) vs 复制(cp)的详细区别
linux·复制·硬链接·cp·ln
不穿格子的程序员1 个月前
Redis篇9——Redis深度剖析:
数据库·redis·多线程·事务回滚·ap·cp
_OP_CHEN3 个月前
Linux系统编程:(三)基础指令详解(2)
linux·man·more·cat·linux指令·cp·whereis
程序源_hytz1 年前
每日论文5—06TCAS2锁相环电流匹配的gain-boosting电荷泵
cmos·pll·ieee·cp
Betty’s Sweet1 年前
[Linux]:基本指令(上)
linux·指令·重定向·ls·cp·pwd·mv
努力的派大星星2 年前
【Linux】深入探索`cp`命令:文件复制的全面指南
linux·命令·cp