permutation – প্রোগ্রামিং ইন্টারভিউ সমস্যা ১৩

সমস্যাঃ একটি লিস্টে কিছু সংখ্যা থাকবে, সংখ্যাগুলোর সবগুলো বিন্যাস (permutation) বের করতে হবে।

উদাহরণ: লিস্টে যদি [1, 2, 3] থাকে, তাহলে বিন্যাসগুলো হবে –

[1, 2, 3]
[1, 3, 2]
[2, 1, 3]
[2, 3, 1]
[3, 2, 1]
[3, 1, 2]

সমাধানঃ এটি মোটামুটি সহজ একটি সমস্যা। তবে ইন্টারভিউয়ের সময় শুরুতেই একটি প্রশ্ন করে নিতে হবে – সংখ্যাগুলো অনন্য (unique) কী না। এটি না জেনেই হুট করে কোড শুরু করা যাবে না। যদি অনন্য হয়, তাহলে খুব সহজেই রিকার্শন ব্যবহার করে সমাধান করা যায়। আর যদি তা না হয়, তাহলে একটু সতর্ক থাকতে হবে, যেন একটি বিন্যাস একাধিকবার প্রিন্ট করা না হয়।

এরকম সহজ সমস্যা দেওয়ার কারণ হচ্ছে বেসিক রিকার্শন স্কিল পরীক্ষা করা। তারপরও আমার পরিচিত একজন ইন্টারভিউয়ারের মতে, ৮০% প্রার্থী এই সমস্যাটির সমাধান করতে ব্যর্থ হয়। যাই হোক, যারা এর সঙ্গে পরিচিত নয়, তারা শাফায়েতের ব্লগের ব্যাকট্র্যাকিং: পারমুটেশন জেনারেটর আর্টিকেলটি পড়তে পারে।

আমি পাইথন কোড দিচ্ছি –

def permute(i, n):
	if i == n:
		print(r)
		return
	
	for j in range(n):
		if visited[j]:
			continue
		visited[j] = True
		r[i] = a[j]
		permute(i+1, n)
		visited[j] = False

if __name__ == "__main__":
	a = [1, 2, 3, 4]
	r = [0] * len(a)
	n = len(a)
	visited = [False] * n
	permute(0, n)

এখন, এখানে আমি অতিরিক্ত একটি অ্যারে বা লিস্ট ব্যবহার করেছি। যদি সেটি করতে না চাই, তাহলে আরেকভাবে সমস্যাটির সমাধান করা যায়। সেক্ষেত্রে প্রতিটি অবস্থানের জন্য বাকী অবস্থানে যেসব সংখ্যা আছে, তাদের মধ্যে অদল-বদল করতে হবে। কোড হবে এরকম –

def permute2(l, r):
	if l == r:
		print(a)
		return
	
	for i in range(l, r+1):
		a[l], a[i] = a[i], a[l]
		permute2(l+1, r)
		a[l], a[i] = a[i], a[l]

if __name__ == "__main__":
	a = [1, 2, 3, 4]
	r = [0] * len(a)
	n = len(a)
	visited = [False] * n
	permute2(0, n-1)

এখন, যদি বলা হয়, লিস্টের সংখ্যাগুলো অনন্য নয়, একই সংখ্যা একাধিকবার থাকতে পারে, কিন্তু একই বিন্যাস একাধিকবার প্রিন্ট করা যাবে না, তাহলে আমরা দুটি পদ্ধতি প্রয়োগ করতে পারি। প্রথমত একটি সেট ব্যবহার করবো। প্রতিটি বিন্যাস পাওয়ার পরে সেটি সেটে আছে কী না পরীক্ষা করবো, যদি না থাকে, তাহলেই কেবল প্রিন্ট করব এবং সেটে যোগ করে নিব।

def permute3(i, n):
	if i == n:
		tpl = tuple(r)
		if tpl in s:
			return
		s.add(tpl)
		print(r)
		return
	
	for j in range(n):
		if visited[j]:
			continue
		visited[j] = True
		r[i] = a[j]
		permute3(i+1, n)
		visited[j] = False

if __name__ == "__main__":
	a = [1, 2, 3, 1]
	n = len(a)
	r = [0] * n	
	visited = [False] * n
	s = set()
	permute3(0, n)

এখন আমরা যদি সেট ব্যবহার করতে না চাই, তাহলে দ্বিতীয় প্রোগ্রামের কোড একটু পরিবর্তন করে কাজটি করা যায় –

def permute4(l, r):
	if l == r:
		print(a)
		return
	
	for i in range(l, r+1):
		if a[i] in a[l:i]:
			continue
		a[l], a[i] = a[i], a[l]
		permute4(l+1, r)
		a[l], a[i] = a[i], a[l]


if __name__ == "__main__":
	a = [1, 2, 3, 1]
	n = len(a)
	r = [0] * n	
	visited = [False] * n

ওপরের প্রোগ্রামটি কীভাবে কাজ করে, সেটি বুঝতে হলে একটু খাতাকলম নিয়ে বসতে হবে। পরিশ্রম ছাড়া এমনি এমনি প্রোগ্রামিং শেখা যায় না।

যোগফল শূন্য – প্রোগ্রামিং ইন্টারভিউ সমস্যা ৬

সমস্যাঃ একটি পূর্ণসংখ্যার অ্যারেতে তিনটি করে সংখ্যা নিলে কতগুলো পৃথক ত্রয়ী পাওয়া যায়, যাদের যোগফল শূন্য (0) হবে?

যেমন, A = [-1, 0, 1, 2, -1, -4], দেওয়া থাকলে, সমাধান হচ্ছে, (-1, 0, 1) ও (-1, -1, 2). প্রতিটি ত্রয়ীর সংখ্যাগুলো ছোট থেকে বড় ক্রমে লিখতে হবে, মানে -1, 2, -1 লিখা যাবে না, বরং -1, -1, 2 লিখতে হবে।

সমাধানঃ সমস্যাটি খুব সহজেই তিনটি নেস্টেড লুপ ব্যবহার করে সমাধান করা যায়, সেক্ষেত্রে সমাধানের কমপ্লেক্সিট হয় O(n^3). ইন্টারভিউতে এই সমস্যা দিলে প্রথমেই এই কোড লেখা যাব না, বরং ইন্টারভিউয়ারকে জিজ্ঞাসা করতে হবে এবং আমার দৃঢ় বিশ্বাস, ইন্টারভিউয়ার এই সমাধানের কোড লিখে সময় নষ্ট করতে উৎসাহিত করবেন না, বরং কমপ্লেক্সিটি আরো কমাতে বলবেন।

আমরা যদি অ্যারেটি শুরুতেই সর্ট করে নিই, তাহলে সবচেয়ে ভেতরের লুপের বদলে বাইনারি সার্চ ব্যবহার করা যায়, এবং সেক্ষেত্রে কমপ্লেক্সিটি হয়, O(n^2 log n), যা O(n^3)-এর চেয়ে ভালো। কিন্তু সমস্যাটি O(n^2) কমপ্লেক্সিটিতেই সমাধান করা সম্ভব। আমি প্রথমেই বলব, পাঠককে একটু নিজে চেষ্টা করার জন্য। নিজে চেষ্টা করে নিচের যেকোনো একটি লিঙ্কে সমাধান করে যাচাই করা যাবে –
https://www.interviewbit.com/problems/3-sum-zero/
https://leetcode.com/problems/3sum/description/

আমি একটি নমুনা ইনপুট ও আউটপুট দিয়ে দিচ্ছি –

ইনপুট – A = [ 1, -4, 0, 0, 5, -5, 1, 0, -2, 4, -4, 1, -1, -4, 3, 4, -1, -1, -3]

আউটপুট – [[-5, 0, 5], [-5, 1, 4], [-4, -1, 5], [-4, 0, 4], [-4, 1, 3], [-3, -2, 5], [-3, -1, 4], [-3, 0, 3], [-2, -1, 3], [-2, 1, 1], [-1, 0, 1], [0, 0, 0]]

সমস্যাটি আমি আজকে সন্ধ্যায় সমাধান করেছি (আমি পাইথন ব্যবহার করেছি), কিন্তু পুরো সমাধান লিখে দিয়ে পাঠককে প্রোগ্রামিংয়ের আনন্দ থেকে বঞ্চিত করতে চাইছি না।

উল্লেখ্য যে, এই প্রশ্নটি গুগল ও ফেসবুকের ইন্টারভিউতে ইতিপূর্বে জিজ্ঞাসা করা হয়েছে।