Hard Patterns — The Cross-Topic Combo Dictionary¶
Hard problem কালেভদ্রে কোনো নতুন tool। তারা আসলে হাত-ধরাধরি করা দুটো চেনা tool। এই file নাম দিয়েছে সেই আটটা combo-কে, যারা বেশিরভাগ hard interview আর contest problem cover করে — সাথে recognition signal, যাতে প্রত্যেকটা cold অবস্থায় চিনে ফেলতে পারো।
প্রতিটা combo-র জন্য: যে signal-গুলো দেখে সন্দেহ করবে, tool দুটোকে জোড়া দেওয়া এক-বাক্যের thinking tweak, example problem, আর কোন repo folder থেকে সে উত্তরাধিকার পায়।
1. Binary search on the ANSWER + greedy feasibility check¶
- Recognition signals: "minimize the maximum " বা "maximize the minimum "; উত্তরটা একটা জানা range-এর ভেতরের একটামাত্র সংখ্যা; যেকোনো guessed value-র জন্য "এটা কি achievable?" check করা optimum সরাসরি compute করার চেয়ে সহজ; feasibility-টা monotonic (X কাজ করলে X-এর চেয়ে সহজ সবকিছুই কাজ করে)।
- The thinking tweak: উত্তর খোঁজা বন্ধ করো — উত্তরটা guess করো, আর guess-টাকে binary-search করো। কঠিন optimization problem-টা হয়ে যায় log(range)-টা সহজ yes/no প্রশ্ন, প্রত্যেকটার উত্তর দেয় একটা greedy বা linear check।
- Example problems:
- একটা array-কে k ভাগে ভাঙা, সবচেয়ে বড় ভাগের sum minimize করে — LeetCode "Split Array Largest Sum" at leetcode.com।
- খাওয়ার speed-এর problem ("slowest speed that still finishes in time") — LeetCode "Koko Eating Bananas" at leetcode.com।
- Inherits from: binary search (
../03-searching-and-sorting/), greedy reasoning (../10-greedy/থাকলে, নাহলে folder 03), monotonicity-র intuition।
2. Sliding window + hashmap¶
- Recognition signals: "longest/shortest substring or subarray satisfying ___"; property-টা character বা element-এর count জড়ায় ("contains all of", "at most k distinct"); window বাড়ালে/কমালে property-টা monotone আচরণ করে।
- The thinking tweak: Window-র দুটো pointer সামলায় কোথায়; hashmap সামলায় ভেতরে কী আছে। ডান প্রান্ত greedily বাড়াও; বাঁ প্রান্ত গোটাও শুধু যতক্ষণ invariant ভাঙা থাকে (বা, "shortest containing"-এর ক্ষেত্রে, যতক্ষণ সেটা টিকে থাকে)।
- Example problems:
- Minimum Window Substring (LeetCode 76) — সব দরকারি character cover করা shortest window।
- Longest Substring Without Repeating Characters (LeetCode 3)।
- Inherits from: sliding window (
../02-arrays-and-strings/), frequency hashmap (../05-hashing/)।
3. Heap + intervals¶
- Recognition signals: start/end time-ওয়ালা event; "how many simultaneous ___", "minimum rooms/machines/servers"; event-গুলো time order-এ process করো আর সবসময় জানতে হয় active জিনিসগুলোর মধ্যে earliest-ending-টা কোনটা।
- The thinking tweak: Interval-গুলো start দিয়ে sort করো (timeline-টা), আর end time-গুলোর একটা min-heap রাখো (active set-টা)। প্রতিটা নতুন interval-এ, পেরিয়ে-যাওয়া প্রতিটা end time pop করো — heap-এর size-ই হলো live concurrency।
- Example problems:
- Minimum meeting rooms — LeetCode "Meeting Rooms II" at leetcode.com (premium)।
- Merge k Sorted Lists (LeetCode 23) — সেই একই "always need the smallest frontier" instinct, end time-এর জায়গায় list head।
- Heap ছাড়া warm-up: Merge Intervals (LeetCode 56)।
- Inherits from: heaps (
../08-heaps-and-priority-queues/), sorting আর sweep thinking (../03-searching-and-sorting/)।
4. Monotonic stack¶
- Recognition signals: "next greater/smaller element"; "how far can each element see"; histogram, skyline, temperature, দেয়ালের মাঝের পানি — যেখানেই প্রতিটা element-এর উত্তর ঠিক করে তার nearest dominating neighbor।
- The thinking tweak: এমন একটা stack রাখো যেটা construction-এর গুণেই sorted থাকে: প্রতিটা নতুন element তার dominate করা সবাইকে pop করে (আর ঠিক সেই pop-এর মুহূর্তেই popped element-দের উত্তর দিয়ে দেয়)। প্রতিটা element একবার push হয়, একবার pop — ভেতরে loop থাকা সত্ত্বেও মোট O(n)।
- Example problems:
- Trapping Rain Water (LeetCode 42) — canonical দেয়াল-আর-পানির আকৃতি (two pointers দিয়েও হয়; দুটোই জানাটাই flex)।
- Daily Temperatures (LeetCode 739) — খাঁটি next-greater drill।
- Inherits from: stacks (
../04-linked-lists/বা এই repo-র stacks-and-queues folder), array scanning (../02-arrays-and-strings/)।
5. Graph + DP (longest path / counting on a DAG)¶
- Recognition signals: dependency বা একমুখী move (prerequisites, "strictly increasing neighbor", versioned states); চাওয়া হয়েছে longest chain বা path-এর সংখ্যা — যা একা BFS দিতে পারে না; move-গুলো কখনো loop করতে পারে না (acyclic), বা strict inequality acyclicity-টা জোর করে আনে।
- The thinking tweak: একটা DAG-এর topological order হলো ready-made একটা DP fill order। Define করো
dp[v]=v-তে শেষ (বা শুরু) হওয়া উত্তর, vertex-গুলো topological order-এ process করো, আর প্রতিটা edge হয়ে যায় একটা করে transition। Memoized DFS একই order implicitly পায়। - Example problems:
- Longest Increasing Path in a Matrix (LeetCode 329) — grid-টা একটা DAG, কারণ move-এ value strictly বাড়ে।
- একটা explicit dependency graph-এ path গোনা বা longest path — CSES "Longest Flight Route" / "Game Routes" at cses.fi/problemset।
- Inherits from: graphs + topological sort (
../09-graphs/topological-sort.md), DP-র state thinking (../12-dynamic-programming/)।
6. Segment tree / BIT for order statistics¶
- Recognition signals: "for each element, how many earlier/later elements are smaller/greater"; "count inversions"; "rank of each element as it arrives"; n 10⁵ পর্যন্ত গেলে O(n²) pair-counting brute force; value হয়তো বিশাল কিন্তু সংখ্যায় মাত্র n-টা।
- The thinking tweak: Tree-টাকে position নয়, value-গুলোর উপর একটা frequency table হিসেবে ব্যবহার করো। Array-টা এক দিকে scan করো; প্রতিটা element-এ, query করো already-seen কতগুলো value একটা range-এ পড়ে, তারপর element-টা insert করো। বিশাল value-গুলোকে আগে coordinate-compress করে rank বানাও।
- Example problems:
- Count of Smaller Numbers After Self (LeetCode 315) — নামটাই এর।
- Reverse Pairs (LeetCode 493) — একই engine, queried range-এ একটা মোচড়।
- Inherits from: Fenwick/segment trees (
../11-segment-tree-and-fenwick-tree/), compression-এর জন্য sorting (../03-searching-and-sorting/)।
7. DP + bitmask¶
- Recognition signals: n ≤ ~20 (পুরো problem-solving-এর সবচেয়ে জোরালো signal); "use each element exactly once", "visit every city", "assign workers to jobs"; স্বাভাবিক state-টাকে মনে রাখতেই হয় কোন subset খরচ হয়ে গেছে।
- The thinking tweak: Subset-টা নিজেই হয়ে যায় DP-র state, একটা integer-এর bit হিসেবে encode করা — affordable শুধু এজন্যই যে 2²⁰ ≈ 10⁶।
dp[mask](প্রায়ইdp[mask][last]), transition-গুলো আর-একটা করে bit set করে। ছোট্ট n কোনো উপহার নয়; এটা একটা নির্দেশ। - Example problems:
- ≤ 20 শহরের উপর traveling-salesman-ধাঁচের minimum tour (classic; CSES-এ আছে "Hamiltonian Flights" at cses.fi/problemset)।
- ≤ 16-টা item-কে k-টা সমান দলে ভাগ করা — LeetCode "Partition to K Equal Sum Subsets" at leetcode.com।
- Inherits from: DP (
../12-dynamic-programming/patterns.md, family 7), bit manipulation (math level 4), subset enumeration (math level 11)।
8. Meet-in-the-middle¶
- Recognition signals: n ≈ 30–40 — 2ⁿ-এর জন্য বড় বেশি, DP-র জন্য বড় বেশি unstructured (value astronomically বিশাল, index করার মতো ছোট কোনো capacity নেই); sum/score শর্তসহ "choose any subset"।
- The thinking tweak: 2⁴⁰ impossible কিন্তু 2²⁰ সহজ — তাই set-টা অর্ধেক করো, প্রতিটা অর্ধেকের সব subset enumerate করো (প্রতিটা 2²⁰), তারপর অর্ধেক দুটোকে জোড়ো sorting + binary search বা two pointers দিয়ে। Exponential খরচটা square-root হয়ে যায়।
- Example problems:
- n ≈ 40 আর value বিশাল হলে sum ≤ / = একটা target-এর subset গোনা — CSES "Meet in the Middle" at cses.fi/problemset।
- দুই ভাগে ভাঙা closest subset sum — LeetCode "Partition Array Into Two Arrays to Minimize Sum Difference" at leetcode.com।
- Inherits from: math level 11-এর subset enumeration আর meet-in-the-middle idea (
../01-math-based-programming-fundamentals/), binary search (../03-searching-and-sorting/)।
The recognition cheat sheet¶
| You read... | Suspect combo |
|---|---|
| "minimize the maximum" / "maximize the minimum" | 1 — binary search on answer |
| "longest substring with counts condition" | 2 — window + hashmap |
| "minimum rooms / max simultaneous" | 3 — heap + intervals |
| "next greater" / walls / histogram / water | 4 — monotonic stack |
| "longest chain through dependencies / increasing moves" | 5 — graph + DP |
| "for each element, count smaller before/after" | 6 — tree for order statistics |
| "n ≤ 20, use each exactly once" | 7 — DP + bitmask |
| "n ≈ 40, any subset, huge values" | 8 — meet-in-the-middle |
A worked recognition, start to finish (শুরু থেকে শেষ, একটা কাজে-করা চেনা)¶
ছদ্মবেশী একটা prompt-এ dictionary-টা fire করতে দেখো:
"A shipping company must move
npackages, in the given order, withinddays. Each day's load is the sum of that day's packages. What is the smallest ship capacity that gets everything delivered on time?"
read 1 (story): ships, packages, days — operational wrapper, ignore
read 2 (shape): answer is ONE number (a capacity); "smallest capacity
that still works" = minimize a maximum daily load
signal match: "minimize the maximum" -> combo 1, binary search on answer
monotone check: if capacity C works, every C+1 works ✓
feasibility: given a guessed C, greedily pack days left to right,
count days used, compare to d — O(n) per guess
plan: binary search C over [max(package), sum(packages)],
O(n log(sum)) total
ত্রিশ সেকেন্ডের signal-matching বদলে দিল সেটাকে, যা নাহলে হতো একটা চালাক idea-র জন্য অন্ধ হাতড়ানো। (এই task-টার public version হলো LeetCode "Capacity to Ship Packages Within D Days" at leetcode.com।)
Combos love company: frequent pairings (combo-রা সঙ্গ ভালোবাসে)¶
Hard problem মাঝেমধ্যে combo-গুলোকে শিকলে গাঁথে। যে জুটিগুলোর জন্য তৈরি থাকা উচিত:
- 1 + 3: একটা time/capacity binary search করো, যেখানে প্রতিটা feasibility check একটা heap দিয়ে interval sweep করে।
- 5 + 6: এমন একটা DAG-এর উপর DP, যার transition একটা range-এর প্রশ্ন করে — উত্তর দেয় folder 11-এর একটা segment tree (value-গুলোর উপর tree দিয়ে LIS-ও ঠিক এভাবেই O(n log n)-এ পৌঁছায়)।
- 2 + 4: Window-র problem, যেখানে "window-র ভেতরের best"-এর জন্য hashmap-এর বদলে লাগে একটা monotonic deque।
- 7 + 1: ছোট set-এর জন্য bitmask DP, আর যে threshold-টা জিজ্ঞেস করা হচ্ছে তার জন্য binary search।
জুটিগুলো আলাদা করে practice করতে হবে না — প্রতিটা অর্ধেক চিনতে পারাই যথেষ্ট, কারণ fusion-টা সবসময়ই "এক combo অন্যটার ভেতরের প্রশ্নের উত্তর দেয়"।
How to drill this file (এই file কীভাবে drill করবে)¶
- আটটা combo-ই একবার পড়ো, তারপর এক সপ্তাহ প্রতিদিন শুধু signals-এর লাইনগুলো আবার পড়ো।
problems/README.md-এর প্রতিটা problem-এর জন্য, statement পড়ার আগে শুধু title আর constraint থেকে তোমার combo-আন্দাজটা লেখো। Hit rate track করো; ~70%-এর উপরে মানে dictionary-টা বসে গেছে।- আন্দাজ miss করলে problem note-এ এক লাইন লেখো: "আমি X আন্দাজ করেছিলাম কারণ ; আসলে Y ছিল কারণ ।" Miss-গুলো hit-এর চেয়ে দ্রুত signal শেখায়।
- সপ্তাহে একবার Codeforces problem set বা CSES খোলো, পাঁচটা random statement পড়ো, আর ONLY classify করো — solve নয়। Solve করার চাপ ছাড়া classification-ই সবচেয়ে সস্তা recognition training।
- যেকোনো জায়গায় যেকোনো hard problem-এ আটকালে, হতাশ হওয়ার আগে cheat sheet-টা উপর থেকে নিচে checklist হিসেবে চালাও। "আটটার একটাও মেলে না" বিরল — আর সত্যি হলে সাধারণত মানে problem-টা ভয়ের পোশাক-পরা একটা single-tool problem।