020 — Reverse Nodes in k-Group¶
Source¶
- Original source: Classic linked list exercise
- Platform: LeetCode — https://leetcode.com/problems/reverse-nodes-in-k-group/
- Topic: linked list
- Difficulty: Hard
- Pattern: segmented reversal + group counting
- Basic idea inherited from: problem 13 (sublist reversal) একটা loop-এ, group counting সহ
1. Problem in simple words¶
একটা linked list আর একটা সংখ্যা k দেওয়া। তোমাকে list-টাকে পরপর k-টা node করে নিয়ে প্রতিটা group আলাদাভাবে reverse করতে হবে। শেষে যদি k-এর চেয়ে কম node পড়ে থাকে, সেগুলো যেমন আছে তেমন থাকবে (reverse হবে না)।
list : 1 -> 2 -> 3 -> 4 -> 5 , k = 2
ফল : 2 -> 1 -> 4 -> 3 -> 5 (শেষের 5 একা, তাই অপরিবর্তিত)
k = 3 হলে:
ফল : 3 -> 2 -> 1 -> 4 -> 5 (শেষের 4,5 দুটো, k-এর কম, অপরিবর্তিত)
2. Which basic idea does this inherit from?¶
ভিত্তি problem 13 (Reverse Linked List II — একটা অংশ reverse) আর problem 1-এর full reversal। সেখানে আমরা শিখেছি একটা নির্দিষ্ট segment কীভাবে উল্টে আবার বাকি list-এর সাথে সেলাই করতে হয়। এখানে সেটাই বারবার — পুরো list জুড়ে k-size segment করে, সাথে নতুন একটা শর্ত: group-এ k-টা node আছে কিনা আগে গুনে নেওয়া।
3. What is the hidden math or logic?¶
লুকানো logic: list-কে floor(n/k) টা পূর্ণ group আর শেষে একটা অসম্পূর্ণ অবশিষ্ট (n mod k node) হিসেবে দেখা। শুধু পূর্ণ group গুলো reverse হয়। প্রতিটা group reverse করার পরে দুটো সেলাই দরকার: group-এর নতুন head আগের অংশের সাথে, আর group-এর পুরোনো head (যা এখন লেজ) পরের অংশের সাথে। recursion এই সেলাই স্বয়ংক্রিয় করে দেয়।
4. Which data structure is needed?¶
কোনো নতুন structure লাগে না — শুধু কয়েকটা pointer (prev, cur, nxt) আর একটা counter (group-এ k node আছে কিনা গুনতে)। recursion ব্যবহার করলে call stack-এ O(n/k) depth।
5. Why this data structure fits¶
Linked list-এ একটা segment reverse করা মানে শুধু কিছু arrow ঘোরানো — O(1) extra (problem 1-এর তিন-pointer dance)। array হলে block-by-block উল্টে রাখতে সরানো-সরানি লাগত; এখানে শুধু link বদলালেই হয়। তাই pointer + counter-ই যথেষ্ট, আর recursion group-গুলোর মধ্যে সেলাইটা পরিষ্কার রাখে।
6. Real-life analogy¶
একসারি বই তাকে রাখা। তুমি প্রতি kটা বই করে নিয়ে সেই কটার ক্রম উল্টে দিচ্ছ, তারপর পরের k-টায় যাচ্ছ। কিন্তু একটা নিয়ম: একটা গুচ্ছ উল্টানোর আগে গুনে দেখো পুরো k-টা বই আছে কিনা — না থাকলে শেষের ওই কটা বই ছুঁয়ো না, যেমন আছে থাক।
7. Visual explanation¶
1 -> 2 -> 3 -> 4 -> 5, k = 2:
group 1: গুনে দেখো 2 node আছে (1,2) → reverse → 2 -> 1
group 2: গুনে দেখো 2 node আছে (3,4) → reverse → 4 -> 3
শেষ: পড়ে আছে 5 — মাত্র 1 node (< k) → অপরিবর্তিত
সেলাই: (2 -> 1) -> (4 -> 3) -> 5
ফল : 2 -> 1 -> 4 -> 3 -> 5
8. Example input and output¶
Input : 1 -> 2 -> 3 -> 4 -> 5 , k = 2 -> Output: 2 -> 1 -> 4 -> 3 -> 5
Input : 1 -> 2 -> 3 -> 4 -> 5 , k = 3 -> Output: 3 -> 2 -> 1 -> 4 -> 5
Edge 1 (k = 1): 1 -> 2 -> 3 , k=1 -> Output: 1 -> 2 -> 3 (বদল নেই)
Edge 2 (n, k-এর গুণিতক): 1->2->3->4 , k=2 -> Output: 2 -> 1 -> 4 -> 3
Edge 3 (একটা node): 1 , k=2 -> Output: 1
Edge 4 (খালি): None , k=2 -> Output: None
9. Brute force thinking¶
সরল চিন্তা: সব value একটা array-তে তোলো। তারপর array-তে প্রতি k-size block আলাদা করে reverse করো (শেষ block-এ k-এর কম থাকলে ছেড়ে দাও), তারপর সেই value দিয়ে নতুন list বানাও বা পুরোনো node-এ বসাও।
10. Why brute force is slow¶
Time O(n) হলেও সব value array-তে তুলতে O(n) extra space লাগে — linked list-এ pointer ঘুরিয়ে in-place করলে যা লাগত না। Interview-তে আসল চ্যালেঞ্জ হলো extra array ছাড়া, শুধু arrow ঘুরিয়ে group-by-group reverse করা (O(1) extra, recursion বাদে)।
11. Key observation¶
মূল observation: একটা group reverse করার আগে নিশ্চিত হও সেখানে পুরো k-টা node আছে। k node আগে গুনে নিলে দুটো সুবিধা — (১) অসম্পূর্ণ শেষ group ভুলে reverse হয় না, (২) reverse-এর পরে পরের group-এর শুরু (গোনার সময় থেমে যাওয়া node) হাতেই থাকে, সেলাই সহজ হয়।
12. Optimized intuition¶
প্রতি group-এ: আগে k ঘর এগিয়ে গুনে দেখো k node আছে কিনা; না থাকলে এই অংশ যেমন আছে ফেরাও। থাকলে — বাকি list (k-তম node থেকে শুরু) recursively সমাধান করো, সেটার ফল হবে এই group-এর reversed অংশের পরের অংশ (prev)। তারপর এই k node-কে problem 1-এর dance দিয়ে reverse করো, প্রতিটার arrow পিছনের prev-এর দিকে ঘুরিয়ে। group-এর নতুন head ফেরাও।
13. Thinking tweak¶
মোচড়: "পুরো list একসাথে" না ভেবে ভাবো — "একটা group reverse করি, বাকিটার দায়িত্ব recursion-কে দিই।" আর reverse করার আগে k গুনে নাও — এই এক গোনা-ই অসম্পূর্ণ শেষ group-কে রক্ষা করে আর পরের group-এর শুরুটা হাতে এনে দেয়।
14. Step-by-step dry run¶
Input 1 -> 2 -> 3 -> 4 -> 5, k = 2:
- গুনো:
1, 2— 2 node আছে; থামার পরnode = 3। prev = reverse_k_group(3, 2)— recursion:- গুনো
3, 4— আছে;node = 5। prev = reverse_k_group(5, 2)→ গুনে মাত্র 1 (< 2) →5ফেরাও।3, 4reverse, লেজ 3-এর পরে 5 জোড়া →4 -> 3 -> 5; ফেরাও4।- এখন
prev = 4 -> 3 -> 5;1, 2reverse, লেজ 1-এর পরেprevজোড়া →2 -> 1 -> 4 -> 3 -> 5। - ফেরাও
2। ফল:2 -> 1 -> 4 -> 3 -> 5।
15. Python solution¶
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def reverse_k_group(head, k):
# ১) সামনে k node আছে কিনা গুনো
node = head
count = 0
while node and count < k:
node = node.next
count += 1
if count < k:
return head # k-এর কম — যেমন আছে তেমন থাক
# ২) বাকি অংশ আগে সমাধান করো (recursion); এটাই reversed group-এর পরের অংশ
prev = reverse_k_group(node, k)
# ৩) প্রথম k node reverse করো, arrow পিছনের prev-এর দিকে
cur = head
for _ in range(k):
nxt = cur.next
cur.next = prev
prev = cur
cur = nxt
return prev # group-এর নতুন head
# ---- helpers (test-এর জন্য) ----
def build(values):
dummy = ListNode()
tail = dummy
for v in values:
tail.next = ListNode(v)
tail = tail.next
return dummy.next
def to_list(head):
out = []
while head:
out.append(head.val)
head = head.next
return out
# ---- tests ----
assert to_list(reverse_k_group(build([1, 2, 3, 4, 5]), 2)) == [2, 1, 4, 3, 5]
assert to_list(reverse_k_group(build([1, 2, 3, 4, 5]), 3)) == [3, 2, 1, 4, 5]
assert to_list(reverse_k_group(build([1, 2, 3, 4, 5]), 1)) == [1, 2, 3, 4, 5]
assert to_list(reverse_k_group(build([1, 2, 3, 4, 5, 6]), 3)) == [3, 2, 1, 6, 5, 4]
assert to_list(reverse_k_group(build([1]), 2)) == [1]
assert to_list(reverse_k_group(build([]), 2)) == []
print("সব test pass!")
16. Line-by-line code explanation¶
- গোনা-loop (
while node and count < k) — k ঘর এগিয়ে দেখো group-এ পুরো k node আছে কিনা; থামলেnode= k-তম node (পরের group-এর শুরু)। if count < k: return head— অসম্পূর্ণ শেষ group, অপরিবর্তিত ফেরাও।prev = reverse_k_group(node, k)— বাকি list আগে সমাধান; এর ফলই হবে এই group-এর লেজের পরে জোড়া অংশ।- reverse-loop — problem 1-এর তিন-pointer dance, ঠিক k বার; প্রতিটা arrow পিছনের
prev-এর দিকে ঘোরে, তাই group reverse হয়ে আপনাআপনি পরের অংশের সাথে সেলাই হয়। return prev— k বার পরেprev= reversed group-এর নতুন head।
17. Output walkthrough¶
build([1,2,3,4,5]), k=2 → প্রথম group (1,2) reverse, বাকিটা recursion-এ (3,4) reverse আর 5 একা → 2->1->4->3->5 → [2,1,4,3,5] — assert pass। k=3, k=1, k-এর গুণিতক, একক node, খালি — সব pass; শেষে print: সব test pass!।
18. Time complexity¶
O(n) — প্রতিটা node-এ একবার গোনা হয় আর একবার reverse হয় (মোট ধ্রুবক-গুণ কাজ)। তাই রৈখিক।
19. Space complexity¶
O(n/k) — recursion stack প্রতি group-এ একবার গভীর হয়, মোট n/k level। (iterative লিখলে O(1)-এ নামানো যায়, কিন্তু সেলাই-pointer বেশি লাগে।)
20. Common mistakes¶
- k গোনার আগেই reverse শুরু করা — তখন অসম্পূর্ণ শেষ group-ও ভুল করে উল্টে যায়।
- reverse করার সময় group-এর লেজকে পরের অংশের সাথে জোড়াতে ভুলে যাওয়া — এখানে
prevশুরুতেই recursion-এর ফল ধরায় সেলাই আপনিই হয়; না বুঝলে অংশ হারায়। for _ in range(k)-এর বদলে value-শর্তে reverse করা — তখন কতগুলো node উল্টেছে তার হিসাব এলোমেলো।- খালি list বা k=1 আলাদা না ভাবা (যদিও এই code-এ এমনিতেই সঠিক)।
21. Which basic problem this inherits from¶
ভিত্তি: full reversal (001-reverse-linked-list.md) আর segment reversal (problem 13 — Reverse Linked List II)। এখানে সেই segment-reverse-কে group counting সহ পুরো list জুড়ে বারবার চালানো হয়েছে।
22. Similar harder problems¶
- Reverse Linked List II (একটা অংশ reverse) — https://leetcode.com/problems/reverse-linked-list-ii/ (এই tracker-এর #13)
- Swap Nodes in Pairs (k=2-এর বিশেষ রূপ) — https://leetcode.com/problems/swap-nodes-in-pairs/ (#12)
- Rotate List — https://leetcode.com/problems/rotate-list/ (#16)
23. Pattern learned¶
Segmented reversal with counting: group-এ k node আছে কিনা আগে গুনে, তারপর সেই segment reverse করে recursion/loop-এ পরেরটার সাথে সেলাই — block-wise list rearrange-এর সাধারণ কৌশল।
24. Final summary¶
ভবিষ্যতের আমাকে: "k করে reverse? আগে k গুনো — পুরো group থাকলে reverse করো, বাকিটা recursion-কে দাও; না থাকলে অবশিষ্ট অংশ ছেড়ে দাও।" গোনা-আগে, উল্টানো-পরে — এটাই অসম্পূর্ণ শেষ group বাঁচানোর চাবি।
মনে রাখার নিয়ম (legal): সব নিজের ভাষায় লেখা; problem statement copy করা হয়নি; official link শুধু attribution-এর জন্য; "asked by Google/Amazon" দাবি নেই — এটা একটা common interview pattern।