একটি অনন্য সমস্যা: দেওয়া দুটি সংখ্যা 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 (যখন অ্যারে সর্টেড)।