Meta-learning, and what Chinese OI Gets Right About Learning Algorithms
Why "patterns" are the wrong abstraction, what you should actually memorize, and why the difference matters more now.
I've spent a lot of time looking at how strong competitive programmers learn, particularly Chinese OI / competitive programming communities, and the difference compared to mainstream interview prep is honestly pretty striking.
This is obviously not some claim that Chinese students are inherently better at algorithms. The strongest competitive programmers in the US, India, Eastern Europe, Japan, Korea, etc. train in many of the same ways. What I am comparing is the dominant learning culture around Chinese OI against the mass-market interview-prep culture that became popular in the West and India.
The latter is extremely familiar by now. Do NeetCode 150 or Striver A-Z. Learn the topics in order. Memorize the common patterns. Re-solve the questions you failed. Watch a video when you get stuck. Eventually you build a large enough library that when an interview question appears, you can hopefully recognize what "pattern" it belongs to.
This was not necessarily bad advice. In fact, for a relatively standardized 2021-era interview process, I think it may have been close to optimal if your only objective was getting an offer quickly. My problem is that an interview-specific shortcut gradually became a theory of how people are supposed to learn problem solving. With AI changing how interviews are structured, and how its "higher entropy" which I'll get to in a bit, I think this outdated method / mentality has failed many candidates in the current era.
When I read people like Endless Cheng, or older competitive programming blogs like On "is this greedy or DP", forcing and rubber bands by -is-this-fft-, the emphasis is noticeably different. Algorithms still matter. Patterns still matter. Memorization still matters. But these things are treated as tools that sit downstream of understanding the problem, rather than the process that replaces understanding it. This nuance of spending time to reduce a problem, thinking and understanding seems to always get lost in the western interview community.
That distinction explains why many beginners stay stuck, why so many people are frustrated with Leetcode as problems get harder.
Memorization and understanding
Before anything else, I want to be precise about what I mean by "memorization", because a surprising amount of disagreement comes from using the word to mean several different things.
When I say something is memorized, I simply mean that you can retrieve it without reconstructing it from scratch every single time. That says absolutely nothing about whether you understand it.
You can memorize Dijkstra line-by-line without understanding why relaxation works. You can also understand Dijkstra completely, know its proof, know exactly why negative edges invalidate the argument, and still have the implementation memorized so thoroughly that you can write it almost without thinking.
These are not opposites. Memorization and understanding are mostly orthogonal.
| Weak understanding | Strong understanding | |
|---|---|---|
| Weak retrieval / fluency | You neither know it nor understand it well | You can reconstruct it, but doing so is slow |
| Strong retrieval / fluency | Rote memorization | Internalized knowledge |
The bottom-right cell is where you actually want to end up. In practice, most people end up closer to bottom-left where rote memorization is.
I used to tell people to "stop memorizing", which often gets taken the wrong way. A common objection when beginners hear that is "If I don't memorize these algorithms like Dijkstra's, you will not come up with it". I agree with that, and that's not what I'm suggesting. In hindsight, what I want to say is "stop rote memorizing", which is a learning technique that relies on repeating information until it can be recalled verbatim without necessarily understanding its deeper meaning. I've seen even beginners suggesting to each other to just rote memorize the structure, sliding window templates. Understanding more is what people should be doing.
A strong programmer should absolutely have Dijkstra "memorized cold". You should know how to implement it, its complexity, what it guarantees, the assumptions it needs, and what every important line of the implementation is doing. You should not spend ten minutes of an interview rediscovering priority queues and relaxation.
In fact, once you understand an algorithm deeply enough, using it as a black box is desirable.
Suppose you have already learned why Dijkstra works. You understand that dist[v] stores the best path discovered so far, that relaxation constructs a better candidate path through , and that non-negative edge weights are what let us permanently finalize the minimum unsettled distance. You could reproduce the correctness argument if somebody asked.
During an actual problem, however, you do not need to replay that proof in your head every time.
You can compress all of that into something like
That is abstraction, not ignorance.
A mathematician does not re-prove every theorem before using it. A programmer does not re-derive a hash table every time they create an unordered_map. Understanding means you can open the black box when necessary. Expertise means you usually do not have to.
So the problem was never "memorization", its "rote memorization" and "lack of understanding"
Tools, ideas, and observations
When people say pattern in interview prep nowadays, they usually mean technique / tool. They list binary search, sliding window, or dynamic programming. Those are methods you use to solve a problem. I want to distinguish the structure you recognize from the method you apply.
| Term | What I mean |
|---|---|
| Technique / tool | Something reusable with a known mechanism and contract, such as Dijkstra, DSU, binary search, prefix sums, a segment tree, DFS, etc. |
| Observation | A fact you derive about the particular problem in front of you |
| Idea | A reusable reasoning operation that helps you discover observations or reformulate the problem |
| Pattern | A recurring relationship or structure in a problem, such as a monotone boundary between infeasible and feasible choices |
An observation is almost like a tiny theorem. Given the information in the problem , you manage to establish some useful fact :
Maybe every operation preserves parity. Maybe an optimal answer can never contain a particular configuration. Maybe extending an interval can only increase some quantity. Maybe two apparently different states are actually equivalent.
An idea is one level more abstract. "Look for an invariant" is an idea. "Reverse the process" is an idea. "Characterize all reachable states" is an idea. "Add information to the state until the future depends only on the current state" is an idea. "Turn the optimization problem into a feasibility problem and check whether feasibility is monotone" is an idea.
These are reusable, but they are not solution templates.
Then, suppose you establish that once a candidate answer is feasible, every larger answer is feasible too. The pattern is a monotone boundary between infeasible and feasible answers. Binary search is the technique you can use to find that boundary. The pattern describes a property of the problem; the technique gives you a procedure for solving it.
The observation work is establishing that feasibility is monotone in this particular problem. Calling everything a pattern makes it easy to skip that step and jump straight to applying binary search because the problem looks familiar. So what most people call "patterns", they're often combining multiple concepts, which loses nuance.
Pattern first
The pattern-first version looks roughly like
Observation first
The observation-first version looks more like
The pattern has not disappeared. The difference is the reasoning that gets you there.
This is why so many Leetcoders end up using only the pattern. A lot of standard LeetCode interview problems have very little observation work between the statement and the familiar technique. Sometimes the topic tag has already done that work for you. Recognize the category, apply the template, get accepted. I think that explains why this habit is so common: LeetCode rewards it often enough that you can mistake it for the whole skill.
On those problems, it can work. But a problem that takes several observations before the technique becomes visible asks you to do something your practice kept skipping. Knowing more patterns will not automatically teach you how to get from the statement to one of them.
Strong competitive programmers recognize patterns constantly. In fact, they generally recognize them much faster than beginners do.
The difference is where the pattern enters the reasoning process.
If I have already established that my problem is equivalent to shortest paths on a graph with non-negative edge weights, recognizing Dijkstra is exactly what I should do. The difficult and interesting part was often everything that happened before I was allowed to say "Dijkstra".
This is essentially the point -is-this-fft- makes when criticizing questions like "is this greedy or DP?" If an editorial says that some problem is "just DSU + stack", it may have thrown away almost the entire solution. Knowing DSU and a stack is frequently the easy part. The interesting part was discovering the representation and observations that made those tools relevant.
An invariant example
Consider a simple problem.
You have an array of non-zero integers. In one operation, you may choose two adjacent elements and flip both of their signs. You want to maximize the final sum.
A beginner "pattern matcher" immediately start guessing patterns. "maximize"? oh damn. Is this greedy? DP? Something with prefix sums?
But none of those questions are useful yet.
Instead, forget the magnitudes for a moment and represent each sign by a bit:
Flipping two adjacent signs toggles
Now there is an immediate observation.
Every operation changes the number of negative signs by an even amount, so
never changes.
The parity of the number of negatives is an invariant.
That gives a necessary condition on every state we can possibly reach, but a good solver should immediately ask whether it is also sufficient. In other words:
Can I reach every sign configuration having the same parity?
Yes.
Take any target configuration with the same parity. Work from left to right. If the sign at position is wrong, flip and . This permanently fixes position . After processing the first positions, the final position must also be correct because the target and current configurations have the same parity.
So we have actually characterized the entire state space:
Now the solution is almost trivial.
If the original parity is even, make every value positive. If it is odd, exactly one value must remain negative, so choose the element with minimum absolute value.
What was the "pattern"? There barely is one worth remembering.
The important observation was that the parity of negative signs is invariant. The important idea was much more general:
When operations transform a state, find something every operation preserves, then ask whether that invariant completely characterizes reachability.
That idea transfers to problems about strings, graphs, permutations, games, linear algebra over , and things that look nothing like this array problem.
Writing down Pattern: greedy would preserve almost none of what you just learned.
This is what I mean when I say I would rather store ideas and observations than patterns.
What Chinese OI gets right
Even Endless Cheng's beginner material contains distinctions that I rarely see stated clearly in mainstream English interview prep.
He explicitly recommends topic practice while you are learning a technique. Problems using the same 套路, roughly the same method or family of ideas, are useful together because you can see the technique repeatedly from different angles.
That makes perfect sense.
If you have never learned binary search, doing random problems and hoping you spontaneously invent binary search is stupid. Learn binary search. Understand it. Solve several problems where you know it is relevant. Build fluency.
But that is only one phase of training.
After the beginner stage, Endless Cheng also recommends random practice, because knowing the topic in advance has removed part of the problem. If I tell you that the next ten questions are dynamic programming, then every statement arrives with an enormous hint attached:
You are training state design and implementation, but you are no longer training the ability to determine whether DP is even the right model.
So the actual progression is much closer to
This is much more sophisticated than either extreme of "only grind random problems" or "finish every topic in order and keep redoing the sheet forever".
There is a related tradition in Chinese mathematics education called variation teaching (变式教学). One common formulation involves things like multiple solutions to one problem, one solution applied across multiple problems, or one problem with its conditions repeatedly changed. The point is not to produce arbitrary variety. The point is to vary the surface while forcing the student to notice what remains invariant.
That is almost exactly what we want in algorithm training.
Suppose I teach you a standard two-pointer solution, then give you five problems whose statements look almost identical. You can improve at executing the technique.
Now suppose I take one problem and change the condition that made the two-pointer argument valid.
That trains something different.
You have to answer: which fact did my previous solution depend on? Is that fact still true? If not, what remains true?
This is why I like multi-part problems so much. Part 2 should not merely be "Part 1 but bigger". Ideally it removes one assumption that your previous reasoning quietly relied on.
A learner who actually understood Part 1 can identify exactly which lemma just died.
A learner who only remembered the route sees that their code stopped passing.
Struggle is part of studying
Something I like about the Chinese OI learning culture is the expectation that struggling with a problem is part of studying. Being unable to solve it immediately does not mean the session has failed. You are expected to sit with it, try things, and work out why they fail.
Endless Cheng's advice on editorials leaves room for anything from ten minutes to hours of thinking. He also recommends returning to a problem later, and skipping material you cannot yet understand. That is a much healthier expectation than treating every minute without an accepted solution as wasted time.
Try small cases, test a conjecture, or find a counterexample. When you're stuck, read enough of the editorial to find the missing observation, then close it and reconstruct the solution. Following an explanation is easier than producing the reasoning yourself.
Read the constraints
Another difference I notice in strong OI / CP material is that constraints are treated as part of the problem rather than something printed at the bottom.
Suppose
That is information.
It immediately makes complexities around
plausible, which in turn suggests that subsets or states over subsets may be meaningful.
If
then a huge region of the solution space disappears. An idea is almost certainly not the intended one, so now you can reason backward:
and ask what structure would permit that.
This is another example of the difference between guessing blindly and making an informed conjecture.
Strong solvers guess all the time. They just have more evidence behind the guess.
Why patterns took over
I do not think NeetCode 150, Blind 75, Striver A-Z, or similar resources became popular because everyone teaching algorithms was stupid.
They were responding to a particular incentive.
For a long time, software interviews had a fairly narrow distribution. A company needed thousands of ordinary engineers to conduct 45-minute interviews, understand the expected solution, provide calibrated hints, and grade candidates consistently.
That naturally favors relatively standardized questions.
Candidates then report those questions. LeetCode accumulates them. Prep companies identify the recurring categories. Eventually the optimal short-term strategy starts looking like
If your only objective is
and the interview distribution is stable enough, this can be incredibly effective.
I think NeetCode's success is evidence that it was effective.
My criticism is different.
An interview-preparation shortcut got generalized into an entire philosophy of problem solving.
"Learn these patterns" turned into "problem solving is pattern recognition". "Re-solve these 150 questions" turned into the standard prescription for getting better. People started making flashcards mapping questions to techniques, as if the goal was to construct an increasingly large hashmap from problem appearances to known solutions.
This works until the problem moves even slightly outside the hashmap.
The mass-market incentives reinforce it too. "Here are the 15 patterns you need" is a much easier product to sell than "learn to derive useful structure from unfamiliar problems."
The checklist is easier to sell because the work has a visible endpoint. That does not mean it takes less time to become capable of solving an unfamiliar question.
The same thing is especially visible in Indian placement-oriented content, where there is enormous pressure to give students a finite path from college to an OA or job. Again, this is not an argument about Indian competitive programmers. India's strongest competitive programmers obviously train far beyond this. The distinction I care about is Olympiad-style problem-solving culture versus mass-market interview preparation, not nationality.
Recognizing vs. forcing
There is another nuance here that often gets lost.
An expert's brain absolutely does pattern recognition. If you give a very strong competitive programmer a problem, they may say "this smells like flow" after thirty seconds. That intuition is valuable.
But their internal classifier was built on thousands of examples plus an understanding of why those examples worked.
They can usually tell you what features made them suspect flow. They can abandon the hypothesis quickly if one assumption fails. They can reformulate the problem in a different way. They know neighboring techniques and failure modes.
The beginner version often looks very different:
- The statement says "minimum", so maybe DP.
- DP isn't working, so maybe greedy.
- It has a subarray, so sliding window.
This is what -is-this-fft- calls forcing.
The problem is not that the guess was wrong. Guessing is fine.
The problem is that nothing in the problem actually justified the guess.
I think this is why "pattern" is such an unfortunate word for beginners. It encourages them to think the primary task is classification:
But many good problems require you to ==change before there is even a useful label to assign.
You remodel the process as a graph. You discover an invariant. You introduce a state. You sort away irrelevant order. You derive monotonicity. You convert an optimization problem into a decision problem.
Only then does the familiar technique appear.
What AI changes
I used to phrase this as "AI makes memorization obsolete", but I think that is imprecise.
AI makes raw retrieval cheap.
That is different.
You still need internalized knowledge==. In fact, if an AI generates Dijkstra and you do not understand Dijkstra, you have very little ability to judge whether its modeling is valid, whether the complexity is acceptable, or whether a changed requirement invalidates the algorithm.
What AI destroys is the value of recall as the thing that differentiates you.
A model can reproduce every canonical LeetCode solution. It can write an LRU cache. It can give you the standard "design Twitter" architecture. It can emit a segment tree faster than you can type one.
So if an interview is testing nothing beyond
for a known , it is increasingly testing something machines have already commoditized.
This is why I think the interview format is beginning to shift toward higher-entropy tasks rather than simply "harder LeetCode".
Canva publicly described testing modern AI on its traditional computer-science interview questions, watching the models solve them almost immediately, and then redesigning the interview around more ambiguous and iterative work. The interesting signal becomes decomposition, technical judgment, debugging, follow-ups, and whether you can evaluate what the model produced.
Even the Chinese NOI ecosystem is adapting. The 2026 NOI winter camp announcement included a parallel AI-assisted programming test.
This does not mean every company in 2026 suddenly asks amazing interviews. Plenty still ask ordinary LeetCode.
It means the direction of travel makes memorized routes less defensible as a long-term strategy.
An interviewer can take a standard problem and ask:
- What if values can now be negative?
- What if the input is streamed?
- What if updates occur between queries?
- What if memory must be ?
- Why is this greedy step actually safe?
- What changes if goes from to ?
The algorithmic difficulty may not even increase very much.
The entropy does.
You cannot be sure which memorized route survives the change. You need to know why the original solution worked.
System design does this too
This is not limited to DSA.
The system-design equivalent of pattern matching is something like
You can memorize dozens of architectures this way and sound surprisingly competent until somebody changes a requirement.
A stronger process derives the architecture from properties of the system.
What must be strongly consistent? What can be stale? What is the read/write ratio? Which work must happen synchronously? Where is the bottleneck? What happens under partial failure?
Eventually you may decide that Kafka is appropriate.
You should already know Kafka. You are not expected to rediscover distributed logs during the interview.
The skill being tested is why Kafka belongs here.
This is exactly the same distinction as Dijkstra.
How to train
Most of us are obviously not going to join a Chinese national training camp. That is not the useful takeaway anyway.
The transferable part is the training structure.
When learning something new, practice it by topic until the basic mechanics stop consuming most of your working memory. Understand the technique deeply enough that you know its assumptions, invariant, proof idea, complexity, and failure cases. Memorize it if it is important enough to memorize.
Then stop letting the curriculum tell you when to use it.
Mix the problems. Hide the tags. Practice around the edge of what you can currently solve. Sometimes spend a substantial amount of time failing, because trying an idea, falsifying it, and figuring out why it failed is itself part of the training.
When you finally read an editorial, do not reduce the solution to "oh, monotonic stack." Reconstruct the causal chain.
A useful postmortem looks more like this:
| Question | Example |
|---|---|
| What was the key observation? | Every valid configuration preserves parity |
| How could I have discovered it? | Examine exactly what one operation changes |
| What is the reusable idea? | Find an invariant, then test whether it is also sufficient |
| What technique eventually appeared? | Whatever implementation the reduced problem requires |
That is a much better thing to retain than a flashcard saying problem 1847 → monotonic stack.
And once you understand an idea, vary the problem. Change one assumption. Find another problem with a completely different surface but the same underlying reasoning. Ask which part of your proof breaks.
AI is actually extremely useful here if you use it correctly. Instead of immediately asking for the solution, ask it to find a counterexample to your observation. Ask which constraint you have not used. Ask it for the smallest possible hint. Ask it to mutate one condition after you solve the problem. Ask it to produce a different-looking problem that requires the same idea.
That is using AI to increase the quality of the rep rather than remove the rep.
The part we stopped training
So no, I do not think the lesson from Chinese OI is "do not memorize anything".
That would be ridiculous.
The strongest people have more internalized knowledge, not less. Their vocabulary of algorithms, constructions, theorems, implementation tricks, and prior ideas is enormous.
The difference is that this knowledge does not replace reasoning about the problem in front of them.
They can treat Dijkstra as a black box because they understand the box.
They can recognize DP quickly because they have seen thousands of state formulations.
They can guess a technique from intuition because they know what structural evidence would make that guess plausible.
What I want to avoid is training a learner to memorize only the final edge
while deleting the reasoning that connected the two.
A better mental model is
Learn the tools aggressively. Memorize the important ones. Understand them deeply enough to use them as abstractions.
But train the part in the middle too, because that is what lets you solve the problem that was not already in your sheet.
That part of problem solving almost feels like a lost relic in mainstream interview prep. Somewhere along the way, we stopped asking people to think through the problem and started asking them which template they remembered. Chinese OI culture seems much better at keeping the actual thinking visible.
Isn't this slower?
We're optimizing for long-term problem-solving ability. Spending longer understanding one problem can save time across many others because you retain the reasoning and can reuse it when the problem changes.
I think most Leetcoders end up spending far more time than they realize for very little improvement. They grind one topic after another, forget the solutions, then repeat the same sheets before the next interview. They're optimizing for the bare minimum needed to get through a familiar question, so they keep paying for it every time they need to prepare again. Getting accepted today is a poor measure of whether that time made you a better problem solver.
They also miss the insights that transfer beyond interviews. Learning to identify assumptions, model a process, test a conjecture, and explain why something works helps with real engineering and other problems in your life. That is what I want you to keep from the time you spend studying.