Skip to content

013 — Reverse Linked List II

Source

  • Original source: Classic linked list exercise
  • Platform: LeetCode — https://leetcode.com/problems/reverse-linked-list-ii/
  • Topic: linked list
  • Difficulty: Medium
  • Pattern: segmented reversal (head-insertion)
  • Basic idea inherited from: full reversal (problem 1) + সাবধানে boundary সেলাই

1. Problem in simple words

একটা linked list আর দুটো position leftright (১ থেকে গোনা) দেওয়া। শুধু left থেকে right পর্যন্ত অংশটুকু উল্টে দাও, বাকিটা যেমন আছে তেমন থাকবে। এক পাসে করো। নতুন head return করো।

list : 1 -> 2 -> 3 -> 4 -> 5 ,  left = 2 , right = 4
শুধু 2..4 উল্টাও
ফল  : 1 -> 4 -> 3 -> 2 -> 5

2. Which basic idea does this inherit from?

এর ভিত্তি problem 1 (001-reverse-linked-list.md)-এর full reversal। সেখানে পুরো list উল্টানো হয়; এখানে শুধু একটা অংশ। নতুন চ্যালেঞ্জ: উল্টানো অংশের দুই প্রান্ত আবার সঠিকভাবে বাকি list-এর সাথে সেলাই (stitch) করা — না হলে list ভেঙে যায়।

3. What is the hidden math or logic?

লুকানো কৌশল head-insertion: left-এর ঠিক আগের node-কে (prev) একটা স্থির খুঁটি ধরে রাখো। তারপর অংশের ভেতরের প্রতিটা পরের node-কে এক এক করে তুলে এনে prev-এর ঠিক পরে বসাও। এতে ঠিক right − left বার এই "তুলে সামনে বসানো" করলে অংশটা উল্টে যায়, আর boundary দুটো আপনাআপনি ঠিক থাকে।

4. Which data structure is needed?

কোনো extra structure নয় — একটা dummy head (যদি left = 1 হয়ে head বদলায়) আর কয়েকটা pointer (prev, cur, nxt)। O(1) extra space।

5. Why this data structure fits

Linked list-এ একটা node-কে অন্য জায়গায় সরানো মানে শুধু কয়েকটা arrow বদল — O(1), data সরানো লাগে না। head-insertion ঠিক এই সুবিধাটাই খাটায়: prev খুঁটি স্থির রেখে ভেতরের node গুলো সামনে এনে বসানো। dummy head থাকায় left = 1-এর special case আলাদা সামলাতে হয় না।

6. Real-life analogy

একটা বইয়ের তাকের নির্দিষ্ট কয়েকটা বই উল্টো ক্রমে সাজাতে চাও। বাঁদিকের একটা স্থির বইকে খুঁটি ধরে, তার ঠিক ডানপাশের বইটা বারবার তুলে এনে খুঁটির পরে গুঁজে দাও — অংশটুকু উল্টে যায়, আশপাশের সাজানো বই অটুট থাকে।

7. Visual explanation

prev খুঁটি, প্রতিবার cur-এর পরেরটা তুলে prev-এর পরে বসাও। 1->2->3->4->5, left=2, right=4:

dummy -> 1 -> 2 -> 3 -> 4 -> 5
prev = 1 (left-এর আগের node) , cur = 2

তুলে-সামনে-বসাও (right-left = 2 বার):
  nxt=3: 2->4, 3->2, 1->3  →  1 -> 3 -> 2 -> 4 -> 5
  nxt=4: 2->5, 4->3, 1->4  →  1 -> 4 -> 3 -> 2 -> 5

return dummy.next = 1 -> 4 -> 3 -> 2 -> 5

8. Example input and output

Input : 1 -> 2 -> 3 -> 4 -> 5 , left=2 , right=4  -> Output: 1 -> 4 -> 3 -> 2 -> 5

Edge 1 (পুরোটা): 1 -> 2 -> 3 -> 4 -> 5 , left=1 , right=5 -> Output: 5 -> 4 -> 3 -> 2 -> 1
Edge 2 (এক node): 1 -> 2 -> 3 , left=2 , right=2  -> Output: 1 -> 2 -> 3 (কোনো বদল নেই)
Edge 3 (head ঘিরে): 3 -> 5 , left=1 , right=2     -> Output: 5 -> 3

9. Brute force thinking

সরল চিন্তা: left..right অংশের value গুলো একটা array-তে নাও, array উল্টাও, তারপর সেই উল্টানো value গুলো আবার ওই অংশের node-এ বসিয়ে দাও।

2..4 অংশ = [2,3,4] -> উল্টাও -> [4,3,2] -> node গুলোতে বসাও
ফল: 1 -> 4 -> 3 -> 2 -> 5

10. Why brute force is slow

value-copy করলে O(k) extra space লাগে (k = অংশের দৈর্ঘ্য), আর অনেক ক্ষেত্রে value নয়, node উল্টানোই উদ্দেশ্য। head-insertion দিয়ে কোনো array ছাড়াই, এক পাসে, পুরোনো node গুলোর arrow ঘুরিয়েই O(1) space-এ হয়ে যায়।

11. Key observation

মূল observation: পুরো অংশ আলাদা করে উল্টে আবার জোড়ার দরকার নেই। left-এর আগের node-কে খুঁটি ধরে, ভেতরের পরের node-টা বারবার সামনে এনে বসালেই অংশটা উল্টে যায় — এবং দুই প্রান্তের সেলাই আপনাআপনি ঠিক থাকে।

12. Optimized intuition

dummy বসিয়ে prev কে left-এর ঠিক আগের node-এ নাও (left − 1 ঘর এগিয়ে)। cur = prev.next (অংশের প্রথম node, যেটা শেষে অংশের লেজ হবে)। তারপর right − left বার: cur-এর পরের node nxt-কে তুলে prev-এর পরে বসাও (cur.next = nxt.next, nxt.next = prev.next, prev.next = nxt)। শেষে dummy.next

13. Thinking tweak

মোচড়: "অংশটা কেটে, উল্টে, আবার জুড়ব" না ভেবে ভাবো — "একটা খুঁটির পরে ভেতরের node গুলো এক এক করে সামনে এনে বসাই; ঠিক ততবার যতটা লম্বা অংশ।" তাহলে boundary সেলাই আর আলাদা করে ভাবতে হয় না।

14. Step-by-step dry run

Input 1 -> 2 -> 3 -> 4 -> 5, left = 2, right = 4:

  1. dummy -> 1 -> 2 -> 3 -> 4 -> 5; prev = dummy
  2. left − 1 = 1 ঘর এগোও → prev = 1; cur = prev.next = 2
  3. বার ১: nxt = 3; cur.next = nxt.next (=4)2->4; nxt.next = prev.next (=2)3->2; prev.next = nxt (=3)1->3; এখন 1 -> 3 -> 2 -> 4 -> 5
  4. বার ২: nxt = 4; cur.next = nxt.next (=5)2->5; nxt.next = prev.next (=3)4->3; prev.next = nxt (=4)1->4; এখন 1 -> 4 -> 3 -> 2 -> 5
  5. right − left = 2 বার শেষ; return dummy.next = 1 -> 4 -> 3 -> 2 -> 5

15. Python solution

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def reverse_between(head, left, right):
    dummy = ListNode(0, head)         # left=1 হলে head বদলায়, তাই dummy
    prev = dummy
    for _ in range(left - 1):         # prev কে left-এর ঠিক আগের node-এ নাও
        prev = prev.next
    cur = prev.next                   # অংশের প্রথম node (শেষে অংশের লেজ হবে)
    for _ in range(right - left):     # head-insertion ঠিক ততবার
        nxt = cur.next                # তুলে আনার node
        cur.next = nxt.next           # cur অংশের বাকি/পরের দিকে
        nxt.next = prev.next          # nxt অংশের বর্তমান মাথার আগে
        prev.next = nxt               # prev এখন nxt-কে মাথা ধরে
    return dummy.next

# ---- 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_between(build([1, 2, 3, 4, 5]), 2, 4)) == [1, 4, 3, 2, 5]
assert to_list(reverse_between(build([1, 2, 3, 4, 5]), 1, 5)) == [5, 4, 3, 2, 1]  # পুরোটা
assert to_list(reverse_between(build([1, 2, 3]), 2, 2)) == [1, 2, 3]              # এক node
assert to_list(reverse_between(build([3, 5]), 1, 2)) == [5, 3]                    # head ঘিরে
print("সব test pass!")

16. Line-by-line code explanation

  • dummy = ListNode(0, head)left = 1-এ head বদলালেও সহজে ফেরাতে।
  • for _ in range(left - 1):prev কে left-এর ঠিক আগের node-এ নিয়ে যাও।
  • cur = prev.next — উল্টানো অংশের প্রথম node; এটাই শেষে অংশের লেজ।
  • for _ in range(right - left): — head-insertion ঠিক right − left বার।
  • nxt = cur.next — যে node-টা তুলে সামনে আনব।
  • cur.next = nxt.nextcur কে nxt-এর পরেরটার সাথে জোড়ো (লেজ হারায় না)।
  • nxt.next = prev.nextnxt কে অংশের বর্তমান মাথার আগে বসাও।
  • prev.next = nxtprev এখন নতুন মাথা nxt-কে ধরে।
  • return dummy.next — আসল (সম্ভবত বদলানো) head।

17. Output walkthrough

build([1,2,3,4,5])-এ left=2,right=4 দিলে দুই বার head-insertion-এ [1,4,3,2,5]left=1,right=5 হলে পুরোটা উল্টে [5,4,3,2,1]left=right=2-তে শূন্য বার, কোনো বদল নেই। head ঘিরে [3,5],1,2[5,3]। সব assert pass → সব test pass!

18. Time complexity

O(n)prev-এ পৌঁছাতে রৈখিক, তারপর right − left বার head-insertion; মোট list-এর উপর এক পাস।

19. Space complexity

O(1) — শুধু dummy + কয়েকটা pointer; পুরোনো node reuse, extra memory বাড়ে না।

20. Common mistakes

  • তিনটা arrow ভুল ক্রমে সেট করা — cur.next = nxt.next আগে না করলে অংশের পরের node হারায়।
  • prev কে left − 1-এর বদলে left ঘর এগিয়ে নেওয়া — তখন উল্টানো এক ঘর সরে যায়।
  • left = 1 (head বদলায়) case-এর জন্য dummy না নেওয়া।
  • loop চালানো right − left + 1 বার (এক বার বেশি) — boundary ভেঙে যায়; ঠিক right − left বার।

21. Which basic problem this inherits from

ভিত্তি: problem 1 (001-reverse-linked-list.md)-এর full reversal; তার উপর head-insertion + boundary সেলাই যোগ করে অংশ-উল্টানো। dummy head কৌশল problem 2 (002-merge-two-sorted-lists.md) থেকে।

22. Similar harder problems

23. Pattern learned

Segmented reversal via head-insertion: left-এর আগের node-কে খুঁটি ধরে ভেতরের পরের node বারবার সামনে এনে বসাও; right − left বার করলে অংশ উল্টে যায়, boundary আপনাআপনি ঠিক।

24. Final summary

ভবিষ্যতের আমাকে: "অংশ উল্টাতে হলে — dummy নাও, prev কে left-এর আগে নাও, cur = prev.next; তারপর cur-এর পরেরটা right−left বার তুলে prev-এর পরে বসাও।" পুরো reversal-এর ছোট ভাই, শুধু খুঁটি আর গোনা ঠিক রাখো।


মনে রাখার নিয়ম (legal): সব নিজের ভাষায় লেখা; problem statement copy করা হয়নি; official link শুধু attribution-এর জন্য; "asked by Google/Amazon" দাবি নেই — এটা একটা common interview pattern।