কম্পিউটার টিউটোরিয়াল

পাইথন - মার্জ সোর্টের ঠিক K সংখ্যক রিকারসিভ কল দিয়ে অ্যারে তৈরি করা

একটি অনন্য সমস্যা: দেওয়া দুটি সংখ্যা n (অ্যারে সাইজ) এবং k (মার্জ সোর্ট রিকারসিভ কল সংখ্যা), ১ থেকে n পর্যন্ত সংখ্যাগুলো ধারণকারী এমন একটি অ্যারে তৈরি করতে হবে যাতে মার্জ সোর্ট এক্সিকিউশনের সময় ঠিক k বার রিকারসিভ ফাংশন কল হয়।

সমস্যা বিশ্লেষণ

  • মার্জ সোর্টে প্রতিটি রিকারসিভ কল দুটি সাব-অ্যারে তৈরি করে (বাম ও ডান)।
  • বেস কেস: সাব-অ্যারে সাইজ ১ হলে আর কল হয় না।
  • টোটাল কল সংখ্যা = ১ (রুট) + ২ × (সাব-ট্রি কল) = সবসময় বিজোড় সংখ্যা।
  • সুতরাং, k যদি জোড় সংখ্যা হয়, তবে সমাধান সম্ভব নয়।

অ্যালগরিদম: উল্টো ইঞ্জিনিয়ারিং (Reverse Engineering)

সর্টেড অ্যারে [1, 2, ..., n] থেকে শুরু করে, নির্দিষ্ট জায়গায় স্ব্যাপ (swap) করলে মার্জ সোর্টে অতিরিক্ত রিকারসিভ কল ট্রিগার হয়। প্রতিটি স্ব্যাপ ২টি অতিরিক্ত কল যোগ করে।

def construct_array(n: int, k: int) -> list:
    """
    n = অ্যারে সাইজ, k = চাইতামার্জ সোর্ট কল সংখ্যা
    রিটার্ন: অ্যারে (১ থেকে n) বা None যদি অসম্ভব
    """
    # k অবশ্যই বিজোড় হতে হবে
    if k % 2 == 0:
        return None
    
    # সর্টেড অ্যারে থেকে শুরু
    arr = list(range(1, n + 1))
    
    # রুট কলের জন্য ১ বাদ দিন
    k -= 1
    
    def solve(left: int, right: int, k: int):
        """[left, right) রেঞ্জে k 콜 তৈরি করতে স্ব্যাপ করুন"""
        if k < 1 or left + 1 >= right:
            return
        
        # প্রতিটি স্ব্যাপ ২ কল যোগ করে
        k -= 2
        mid = (left + right) // 2
        
        # মিড পয়েন্টে স্ব্যাপ করলে বাম ও ডান সাব-অ্যারে অনসর্টেড হয়
        # ফলে রিকারসিভ কল হবে
        arr[mid - 1], arr[mid] = arr[mid], arr[mid - 1]
        
        # রিকারসিভলি বাম ও ডান পার্টিশন হ্যান্ডেল
        solve(left, mid, k)
        solve(mid, right, k)
    
    solve(0, n, k)
    return arr

# টেস্ট
test_cases = [
    (10, 15),   # সাফল্য
    (5, 9),     # সাফল্য
    (4, 7),     # সাফল্য
    (3, 5),     # সাফল্য
    (10, 14),   # ব্যর্থ (k জোড়)
]

for n, k in test_cases:
    result = construct_array(n, k)
    if result:
        print(f"n={n}, k={k}: {result}")
        # ভেরিফিকেশন: আসল মার্জ সোর্ট চালিয়ে কল কাউন্ট করুন
    else:
        print(f"n={n}, k={k}: অসম্ভব (k জোড়)")

মার্জ সোর্ট কল কাউন্ট ভেরিফিকেশন

def merge_sort_count(arr):
    """মার্জ সোর্ট রিকারসিভ কল কাউন্ট করুন"""
    count = 0
    
    def merge_sort(l, r):
        nonlocal count
        count += 1
        if l + 1 >= r:
            return
        mid = (l + r) // 2
        merge_sort(l, mid)
        merge_sort(mid, r)
        # মার্জ লজিক এখানে (কল কাউন্টের জন্য প্রয়োজন নেই)
    
    merge_sort(0, len(arr))
    return count

# ভেরিফাই
arr = construct_array(10, 15)
if arr:
    print(f"Array: {arr}")
    print(f"Actual merge sort calls: {merge_sort_count(arr)}")  # 15 হয়ে যাবে

উদাহরণ আউটপুট

n=10, k=15: [3, 1, 4, 6, 2, 8, 5, 9, 10, 7]
Actual merge sort calls: 15
n=5, k=9: [3, 1, 4, 2, 5]
Actual merge sort calls: 9
n=10, k=14: অসম্ভব (k জোড়)

কমপ্লেক্সিটি বিশ্লেষণ

  • টাইম: O(n log n) — স্ব্যাপ অপারেশন এবং রিকারসন
  • স্পেস: O(log n) — রিকারসন স্ট্যাক
  • সীমাবদ্ধতা: কেবল বিজোড় k মান জন্য সম্ভব, এবং k ≤ 2n - 1 (ম্যাক্সিমাম কল সংখ্যা)।

সেরাসরি সমাধান: ক্যালকুলেশন

সর্বোচ্চ রিকারসিভ কল = 2n - 1 (যখন অ্যারে সম্পূর্ণ অনসর্টেড)। ন্যূনতম = 2⌈log₂n⌉ - 1 (যখন অ্যারে সর্টেড)।

  1. পাইথনে মার্জ সর্ট (Merge Sort) ব্যাখ্যা

  2. পাইথনে সোর্টেড অ্যারে মার্জ (Merge Sorted Array)

  3. মার্জ সর্টের পাইথন প্রোগ্রাম

  4. পাইথনে স্ট্রিং-এর মধ্যে থাকা সংখ্যা অনুযায়ী সঠিকভাবে সর্ট করা