Thursday, December 8, 2022

Brush (V) - LOJ-1019

 Problem: Brush (V) - LOJ-1019

Given a graph, find the shortest path from 1 to the Nth node. If its not possible to reach the last node simply print "Impossible"




#include "bits/stdc++.h"
using namespace std;


vector< pair < int, int > >adj[111];

void init(){
    for(int i = 0; i<111; i++){
        adj[i].clear();
    }
}

void dijkstra(int N){
    priority_queue< pair < int, int >, vector< pair < int, int > >, greater< pair< int, int > > > Q; 
    vectordistance(111, INT_MAX);
    vectorvisit(111, 0);
    distance[1] = 0;
    Q.push({1, 0});
    while(!Q.empty()){
        auto v = Q.top();
        Q.pop();
        int parent = v.first;
        for(auto v: adj[parent]){
            int child = v.first;
            int cost = v.second;
            if(distance[child] > distance[parent] + cost){
                distance[child] = distance[parent] + cost;
                Q.push({child,distance[child]});
            }
        }
    }
    if(distance[N] == INT_MAX)cout << "Impossible" <> N >> M;
    for(int i = 0; i < M; i++){
        int u, v, w; cin >> u >> v >> w;
        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
    }
    dijkstra(N);
}
 
int main(){
    //ctrl+alt+b
    ios_base :: sync_with_stdio(0); cin.tie(0); cout.tie(0);
    
    int T = 1; cin >> T;
    for(int __ = 1; __ <= T; __++){
        cout <<"Case "<<__<<": ";
        task();
    }
      
return 0;
}

Country Roads - LOJ-1002

 Problem: Country Roads - LOJ-1002


Shortest path problem, 0 থেকে N-1 তম নোডে যাইতে মিনিমাম খরচ বের করতে হবে, কিন্তু একটু আলাদা ভাবে।

হিসাব টা হবে এমন যে,

প্রব্লেমের এক্সাম্পল যদি চিন্তা করি,

0 থেকে 4 যাইতে, হিসাবঃ

0-1 ->cost 2, 1-4-> cost 8, So max cost is 8.

Similarly, 

0-2-4 -> 9

0-3-4 -> 7


From the above cost (8, 9, 7), the minimum cost is 7.

তাহলে আমাদেরকে, ম্যাক্সিমাম থেকে মিনিমাম খরচ টা বের করতে হবে।

Code:



#include "bits/stdc++.h"
using namespace std;

const int maxn = 555;

vector< pair > adj[maxn];
void init() {
	for (register int i = 0; i < maxn; i++) {
		adj[i].clear();
	}
}
vector dijkstra(int source) {
	priority_queue< pair, vector< pair >, greater< pair > > pq;
	vectordistance(maxn, -1);
	vectorvisit(maxn, false);

	distance[source] = 0;

	pq.push({ 0, source });

	while (!pq.empty()) {
		int parent = pq.top().second;
		pq.pop();

		if (visit[parent])continue;
		visit[parent] = true;

		for (auto v : adj[parent]) {
			int child = v.first;
			int cost = v.second;
			if ((distance[child] > max(distance[parent], cost) && distance[child] > -1) || distance[child] == -1) {
				distance[child] = max(distance[parent], cost);
				pq.push({ distance[child], child });
			}
		}
	}
	return distance;
}

void task() {
	init();
	int n, m; cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int u, v, w; cin >> u >> v >> w;
		adj[u].push_back({ v, w });
		adj[v].push_back({ u, w });
	}

	int t; cin >> t;
	vector distance = dijkstra(t);
	for (int i = 0; i < n; i++) {
		if (distance[i] == -1) {
			cout << "Impossible" << endl;
		}
		else cout << distance[i] << endl;
	}
}

int main() {
	//ctrl+alt+b
	ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);

	int T = 1; cin >> T;
	for (int __ = 1; __ <= T; __++) {
		cout << "Case " << __ << ":" << endl;
		task();
	}

	return 0;
}

Wednesday, July 20, 2022

Longest Sub-Array with Sum K

Longest Sub-Array with Sum K 

সহজ প্রবলেম ডেসক্রিপশন,
একটা N সাইজের Array দেয়া থাকবে, একই সাথে একটা টার্গেট Sum দেয়া থাকবে, Array থেকে এমন একটা Subarray বের করতে হবে যার Length হবে ম্যাক্সিমাম. উল্লেখ্যঃ Array তে Negative Number ও থাকতে পারে.

Example:
Array[] = {5, 6, -5, 5, 3, 5, -2, 0}, target sum =  8

All Possible subarray With Sum 8:

{-5, 5, 3, 5}
{3, 5}
{5, 3}

এইখানে সব থেকে বড় সাইজের Subarray হচ্ছে {-5, 5, 3, 5},
যার সাইজ 4. অর্থাৎ এটাই আমাদের কাঙ্ক্ষিত Answer.


Bruteforce Solution:

সহজ ভাবে বলতে গেলে প্রত্যেকবার লুপ চালিয়ে একটা Subarray বের করতে হবে যেটার Sum হবে Target Sum এর সমান।
তাহলে প্রথম কাজ হচ্ছে Subarray Generate করা। দুইটা লুপ চালায়ে আমরা এই কাজ টা করতে পারি। 


Pseudo Code:

        for i = 0 to n-1
              for j = i to n-1
            
    sum+=a[i]
            
     if(sum == target_sum)
                        maximum of (j-i+1)


এক্ষেত্রে Time Complexity হবে  O(n2).


Optimization:

উদাহরনে দেয়া Array টার কথা চিন্তা করি,

Index 0, 1, 2, 3,  4 , 5, 6
 Array 5, 6, -5, 5, 3, -2, 0

Array র শুরু থেকে প্রত্যেকবার Sum করতে করতে সামনে আগাইতে থাকবো, এবং এই Sum কে Index সহ মার্ক করে রাখবো, যেনো পরবর্তীতে এটা ইউজ করতে পারি.


অর্থ্যাত Prefix sum কাজে লাগবে এইখানে, আর মার্ক করে রাখার জন্য আমরা Map ব্যবহার করতে পারি.

তাহলে , প্রত্যেকবার যখন Sum পাবো, তখন Map এ চেইক করে দেখবো, আগে থেকেই Current Sum , Map এ আছে কিনা ! এর পর যখন দেখবো Current Sum - Target sum এর আগে অল্রেডি দেখে আসছি, অর্থ্যাত Map এ রাখা আছে, তারমানে Current Index থেকে Previous (
Current Sum - Target sum) যেই Index এ দেখে আসছি এই Subarray টার যোগফল Target Sum.আর এই Subarray  র সাইজকে ম্যাক্সিমাম করতে হবে.


Code

Saturday, May 14, 2022

Introduction To Sliding Window Technique.

Array রিলেটেড প্রবলেম সলভিং এর জন্য Sliding Window Technique জানা খুবই জরুরী। যেখানে Repetitive কাজ হয়, সেখানেই Sliding Window Technique ব্যবহার করে খুব সহজেই আমরা Time Complexity কমাইতে পারি। 

Repetitive বলতে মাঝে মাঝে দেখা যায় আমরা একটা প্রবলেম সলভ করতে এমন একটা সল্যুশনে পৌছাইছি যেখানে বারবার সেইম কাজ রিপিট হইতেছে, যেটা কিনা আমরা বাদ দিলেও আমাদের প্রবলেম টা সল্ভ করা সম্ভব।

সাধারনত Fixed সাইজের একটা Window/অংশ/Subarray/Substring নিয়ে 
Sliding Window কাজ করে থাকে। এই রিলেটেড প্রব্লেমে একটা ফিক্সড সাইজের Window দেয়া থাকে, এটাকে লক্ষ্য করে আমাদেরকে সল্যুশনের দিকে আগাইতে হয়।

How to Identify?
১। Array/String/Subarray/Substring
2। Longest/Smallest/Minimum/Maximum/
৩। Window Size

সাধারনত এই তিনটা জিনিসের মাধ্যমেই খুব সহজেই আমরা বুঝতে পারবো কিভাবে একটা প্রবলেম এই টেকনিক এর মাধ্যমে সলভ করা যাবে। 

Sliding Window এবং Two Pointers টেকনিকের মধ্যে ছোটো একটা পার্থক্য আছে।

Two Pointers টেকনিকে আমরা দুই সাইড থেকে আগাইতে থাকি কিন্তু Sliding Window তে একইদিকে "window" আগাইতে থাকে।

নেক্সট কিছু Sliding Window রিলেটেড প্রবলেম সল্ভিং এর মাধ্যমে আমরা আরোও সুন্দর মত এই টেকনিক বুঝতে পারবো । 


Saturday, February 5, 2022

Aggressive Cows | Binary Search Problem

Aggressive Cows - Spoj


সহজ এবং সুন্দর প্রবলেম ডেসক্রিপশন

N টা পজিশন দেয়া আছে আর C গরু দেয়া আছে। এই পজিশন গুলাতে এমন ভাবে এই গরু গুলাকে বসাইতে হবে যেনো যেটা মিনিমাম ডিস্টেন্স ঐটা যেনো ম্যাক্সিমাম হয়।
আরো সুন্দর ভাবে বোঝায়,

ধরি আমাদের পজিশন দেয়া আছে, [1, 2, 4, 8, 9] এইখানে আমাদের কে 3 টা গরুকে বসাইতে হবে।

1

2

4

8

9

Min Distance

C1

C2

C3

 

 

2-1 = 1

C1

C2

 

C3

 

2-1 = 1

C1

C2

 

 

C3

2-1 = 1

C1

 

C2

C3

 

4-1 = 3

C1

 

C2

 

C3

4-1 = 3

 

C1

C2

C3

 

4-2 = 2

 

C1

 

C2

C3

9-8 = 1

এইখানে আমরা ৩ টা গরুকে ৫ টা পজিশনে বিভিন্ন ভাবে বসানোর চেষ্টা করেছি । ছয় নাম্বার কলামে আমরা ছোটো একটা হিসাব করেছি, মিনিমাম ডিস্টেন্স অর্থ্যাত যেকোনো দুইটা গরুর পজিশনের মিনিমাম দুরুত্ব। এখন সব গুলা মিনিমাম ডিস্টেন্স এর দিকে খেয়াল করলে দেখা যাবে 3 হচ্ছে আমাদের ম্যাক্সিমাম নাম্বার। এটাই আমাদের কাঙ্ক্ষিত উত্তর।

সুতরাং আমাদেরকে C টা গরুকে N টা পজিশনে এমনভাবে বসাইতে হবে যেনো তাদের মিনিমাম দুরত্ব টা ম্যাক্সিমাম হয়, আর সেই ম্যাক্সিমাম টাই আমাদের উত্তর।




সল্যুশন আইডিয়া ঃ
প্রথম কথা হচ্ছে পজিশন গুলাকে যে আমাদের সবসময় শর্ট করে দেয়া থাকবে এমন না, সো আমরা চাইলে আমাদের মত করে শর্ট করে নিতে পারি, আর এক্ষেত্রেও আলাদা কমপ্লেক্সিটি আছে সেটাও আমাদের মাথায় রাখতে হবে।


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

যদি আমরা একটু সুন্দর মত চিন্তা করি তাহলে বুঝতে পারবো এন্সার কখনোও প্রথম পজিশন ও শেষ পজিশনের যোগফলের বেশি হবে না। উপরের উদাহরন থেকে শর্ট করার পরে প্রথম পজিশন ১ এবং শেষ পজিশন ৯ , এদের যোগফল ১০ । আমরা কোনো ভাবে ই ১০ এর বেশি উত্তর করতে পারবো না।

এতক্ষনে হইতো বোঝা হয়ে গেছে, আমরা এখানে বাইনারি সার্চ এপ্লাই করবো, কিন্তু কথা হচ্ছে আমরা কিসের উপর বাইনারি সার্চ এপ্লাই করবো ? পজিশন গুলার উপর নাকি গরু গুলার উপর ?

ব্যাপারটা হচ্ছে আমরা উত্তরের উপর বাইনারি সার্চ এপ্লাই করবো। যেহুতু উত্তর কখোনোও প্রথম ও শেষ পজিশনের যোগফলের বেশি হবে না, সুতরাং আমরা জিরো থেকে শুরু করে এই রেঞ্জ এর মধ্যে বাইনারি সার্চ এপ্লাই করতে পারি।

আচ্ছা এতক্ষন বুঝলাম আমরা কোথায় বাইনারি সার্চ এপ্লাই করবো, এখন প্রশ্ন হচ্ছে উত্তরের উপর বাইনারি সার্চ এপ্লাই করে আমরা করবো টা কি ? আর কেনই বা আমরা এমন টা করতেছি ?


ধরি আমরা বাইনারি সার্চ কিভাবে কাজ করে সেটা আগে থেকেই জানি, এইখানে আমরা প্রত্যেকবার একটা মিডিল পজিশন হিসাব করি, এরপর ঐ মিডিল পজিশনের উপর ভিত্তি করে আমরা চেইক করি আমাদেরকে লেইফ সাইডে যাইতে হবে নাকি রাইট সাইডে যাইতে  হবে।

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

তাহলে সল্যুশন সামারি কি দাড়াইলো ?

আমরা একটা রেঞ্জ ধরে নিবো, যেই রেঞ্জ এর মধ্যেই আমাদের উত্তর থাকবে, এর পর একে একে আমরা আমাদের রেঞ্জ এর ভ্যালু গুলা চেইক করবো, তাদেরকে গ্যাপ হিসেবে গরুগুলার  মাঝে ব্যবহার করা যাইকিনা, এই ভাবে আমরা আমাদের মিনিমাম গ্যাপ টা পেয়ে যাবো, যেটা কিনা সব গুলা কম্বিনেশন এর মধ্যে ম্যক্সিমাম।

তাহলে আমাদের টাইম কমপ্লেক্সিটি কি দাড়াইলো ?

আমারা বাইনারি সার্চ করতেছি, এটার জন্য log(N)
একই সাথে প্রত্যেকবার আমরা গ্যাপ চেইক করতেছি ঐটাকে ব্যাবহার করা যাবে কিনা, এটার জন্য O(N)

তাহলে ওভারওল কমপ্লেক্সিটি দাড়াইলো O(NlogN)
N
এর রেঞ্জ সর্বোচ্চ 100,000 হইতে পারে, যেটা ইজিলি পাস করবে।


বুঝতে না পারলে কোড

Tuesday, February 1, 2022

Bipartite Graph Checking

গ্রাফ থিওরি শিখতে গেলেই অনেক আমাদের ধরনের গ্রাফের সাথে পরিচয় হয়ে উঠে, এর মধ্যে বাইপারটাইট গ্রাফ অন্যতম।

এইখানে আমারা গ্রাফের সব নোড গুলাকে দুইটা সেটে বিভক্ত করে ফেলি। এমনভাবে বিভক্ত করি যেনো একই সেটের নোডের মধ্যে কোনো Edge/Vertices না থাকে অর্থাৎ একটা সেটের নোড শুধুমাত্র অন্য আরেকটা সেটের নোডের সাথে কানেক্টেড থাকে।


পাশের চিত্রে খুব সুন্দরভাবে একটা বাইপারটাইট গ্রাফকে দেখানো হইছে। দুইটা সেট U and V তে ভাগ করা হইছে, এবং একই সেটের নোডের মধ্যে কোনো কানেক্টিভিটি নাই।

কোডিং এর ক্ষেত্রেও জিনিস টা সেইম ভাবে চিন্তা করা যায় । আমরা দুইটা সেইটে বিভক্ত না করে, দুইটা কালার দিয়ে রিপ্রেজেন্ট করবো 0 and 1.


DFS মাধ্যমে খুব সহজেই বাইপারটাইট চেইক করা যায়। একটা Visited Array এবং একটা Color Array র মাধ্যমে পুরো প্রসেস টা শেষ হবে। আমরা Boolean Types এর DFS ব্যবহার করবো 

প্রথমে আমরা কালার ১ দিয়ে প্রথম নোড এর DFS চালাবো, এই নোড কে ভিসিটেড এবং কালার এরেতে আপডেট করার পরে, এর এডজেসেন্সি লিস্টে গিয়ে দুইটা জিনিস চেইক করবো 

১। ঐ নোডের চাইল্ডগুলাকে ডিফ্রেন্ট কালার দিয়ে DFS চালালাইলে True/False কি রিটার্ন করে
২। ঐ নোড এবং চাইল্ড সেইম কালার কিনা, সেইম হইলে False

পরিশেষে DFS  True রিটার্ন করবে, কারন এর আগে আমাদের দুইটা কেইস চেইক করার পরেও বাইপারটাইট পাইনাই।

Easy Implementation

Related Problems:
Graph Without Long Directed Paths
BUGLIFE - A Bug’s Life

Sunday, January 30, 2022

Cycle Detection In a Graph

কম্পিটিটিভ প্রোগ্রামিংয়ে আমরা সাধারনত দুই ধরনের গ্রাফ নিয়ে কাজ করে থাকি(আরও অনেক ধরনের গ্রাফ আছে)। ডিরেক্টেড গ্রাফ এবং আনডিরেক্টেড গ্রাফ।
সাধারনত যে সব গ্রাফের দিক নির্দেশক থাকে অর্থাৎ এক নোড থেকে এক্সাক্টলি কোন কোন কোন নোডে যাওয়া যাবে তার দিকে নির্দেশক থাকে সেই গুলাকে ডিরেক্টেড গ্রাফ বলে, অন্যদিকে যে গুলাতে নির্দেশক থাকে না ঐগুলা কে আনডিরেক্টেড গ্রাফ বলে।

গ্রাফের একটা নোড থেকে ভিসিট করা শুরু করলে যদি কোনো একটা টাইমে ঐ নোডেই ফিরে আসা যায় তাহলে বুঝতে হবে এটা একটা সাইকেল।
পাশের ছবিতে দুইটা গ্রাফ আছে , একটা ডিরেক্টেড এবং আরেকটা আনডিরেক্টেড।
ডিরেক্টেড গ্রাফের ১,২ এবং ৩ নাম্বার নোড একটা সাইকেল তৈরি করে।
অন্যদিকে আনডিরেক্টেড গ্রাফের ১,২,৩ এবং ২,৩,৪ দুইটা সাইকেল তৈরি করে।
আমরা এই সাইকেল খোজা কাজটা প্রোগ্রামিং এর মাধ্যমে কিভাবে করতে পারি এবং সাইকেল টাও যেনো প্রিন্ট করতে পারি, এটাই আজকের আলোচ্য বিষয়। All nodes are 0 based.

সাইকেল খুজতে যা যা জানা থাকলে দ্রুত বুঝতে সুবিধা হবেঃ
১ঃ যেকোনো প্রোগ্রামিং ল্যাংগুয়েজ দিয়ে কিভাবে গ্রাফ এর কাজ(ইনপুট/আউটপুট/ট্রাভার্স) করে। 
২ঃ রিকার্সন



ডিরেক্টেড গ্রাফে সাইকেল খোজা

প্রথমে আমরা তিনটা বক্সের সাথে পরিচত হয়ে নিই।
১। সাদা বক্স - শূন্য দ্বারা রিপ্রেজেন্ট করবো (নোড এখোনো ভিজিট হইনাই)
২। ধুসর বক্স - এক দ্বারা রিপ্রেজেন্ট করবো (নোড ভিজিটেড)
৩। কালো বক্স - দুই দ্বারা রিপ্রেজেন্ট করবো (নোডের সব চাইল্ড ভিজিটেড)
একটা Color Array দিয়ে বক্সের কাজ করবো।

একই সাথে সাইকেল এর শুরু এবং শেষ বুঝতে দুইটা ভেরিয়েবল নিবো এবং প্রত্যেকটা নোড এর প্যারেন্ট নোড মার্ক করে রাখতে একটা Array নিবো, যাতে আমাদের সাইকেল প্রিন্ট করতে সুবিধা হয়।

যেহুতু আমরা রিকার্সন জানি, তারমানে আমরা DFS ও জানি, DFS হচ্ছে একটা গ্রাফ Traversing Algorithm. এখানে আমাদের DFS Function টা হবে বুলিয়ান টাইপ্স।

এইগুলা দিয়ে কয়েকটা স্টেপে ডিরেক্টেড গ্রাফে সাইকেল খোজা সম্ভব
১। প্রথমে সব গুলা নোডকে শূন্য(0) দ্বারা মার্ক করে নিবো অর্থাৎ সাদা বক্সে রেখে দিবো, সবগুলা নোডের প্যারেন্ট -1 করে দিবো, Cycle_Start ভ্যারিয়েবল -1 করে রাখবো অর্থাৎ DFS শেষ হবার পরেও Cycle_Start = -1 থাকা মানে কোনো সাইকেল পাইনি।
২। একটা নোড যখন DFS এ ঢুকবে তখন সেটাকে ১ দ্বারা মার্ক করবো অর্থাৎ ধুসর বক্সে রাখবো।
৩। ঐ নোড এর Adjacent অর্থাৎ চাইল্ড নোড গুলা ভিজিট করা শুরু করবো, একটা লুপ দিয়েই করা যায়।
এইখানে দুইটা কেইস হইতে পারে,
-> যদি ঐ নোডের চাইল্ড এখনো সাদা বক্সেই থাকে অর্থাৎ এখনো তাকে ভিজিট না করা হয়ে থাকে তাহলে আমরা সেই চাইল্ডের প্যারেন্ট অর্থাৎ বর্তমান নোডকে মার্ক করবো। সাথে সাথে ঐ চাইল্ড দিয়ে আবার DFS চালাবো একইসাথে দেখবো সে True রিটার্ন করে কিনা।
-> যদি ঐ নোডের চাইল্ড কে আমরা অলরেডি ধুসর বক্সে দেখি অর্থাৎ সে ভিজিটেড(১ দ্বারা মার্ক) থাকে তাহলে বুঝতে হবে এখানে সাইকেল আছে।
যার শুরু ঐ নোড থেকে এবং শেষ ঐ নোডের চাইল্ডে, এটা মার্ক করার জন্য অলরেডি আমরা দুইটা ভ্যারিয়েবল ডিক্লেয়ার করে রাখছি।

৪। ঐ নোডের Adjacent অর্থাৎ সব চাইল্ড ভিজিট করা শেষ হয়ে গেলে আমরা তাকে কালো বক্সে অর্থাৎ ২ দ্বারা মার্ক করে রাখবো, একই সাথে False return করবো। কারন আপাতত আমরা কোনো সাইকেল পাইনি।

Easy Implementation



আনডিরেক্টেড গ্রাফে সাইকেল খোজা

আমরা জানি আনডিরেক্টেড গ্রাফে কোনও দিক নির্দেশক থাকে না অর্থাৎ যেকোনো নোড থেকে বাকি যেকোনো নোডে যাওয়া যাবে। 
এইখানে সাইকেল খোজার জন্য আমাদেরকে কালারিং করার কোনো দরকার নাই কারন যে নোডে আমরা একবার ভিজিট করবো তার চাইল্ড একবার ই ভিজিট  হবে, এর বেশি হবে না। 
সুতরাং আমরা এখানে একটা Visited Array ব্যবহার করবো।

এখানেও কয়েকটা ধাপে আমরা সাইকেল সাইকেল পাইতে পারি।

১। প্রথমে সব গুলা নোড আনভিজিটেড অর্থাৎ Initially False করে রাখবো, সব গুলা নোডের Parent -1 করে রাখবো ।
২। Traversing এর শুরুতে অর্থাৎ নোড যখন DFS এ ঢুকবে তখন ভিজিটিড (True) করে দিবো।
৩। ঐ নোডের চাইল্ড নোড গুলা Traverse করবো, একটা লুপ চালিয়েই করা যাবে, চাইল্ড যদি তার প্যারেন্টের এর সমান হয় তাহলে ঐ চাইল্ড কে ইগ্নোর করবো।

চাইল্ড ভিজিটিং এর ক্ষেত্রে দুইটা কেইস হইতে পারে,
->  যদি চাইল্ড নোড ভিজিটেড থাকে তাহলে আমরা এখানে সাইকেল পাবো,একই ভাবে আগের মত সাইকেলের শুরু এবং শেষ মার্ক করবো। একই সাথে True Return করে দিবো।

এর পর চাইল্ড এর Parent নোড আপডেট করবো।

-> চাইল্ড কে তার প্যারেন্ট নোড দিয়ে আবার DFS এ চেইক করবো True Return করে কিনা।
৩। সব শেষে False Return করবো।

Easy Implementation



ডিরেক্টেড এবং আনডিরেক্টেড গ্রাফের সাইকেল প্রিন্টিং

ডিরেক্টেড এবং আনডিরেক্টেড দুই ক্ষেত্রেই সাইকেল প্রিন্টিং এর কাজ টা সেইম।
আমরা দুই ক্ষেত্রেই প্রত্যেকটা Node এর Parent মার্ক করে রাখছি একই সাথে সাইকেলে র শুরু এবং শেষ মার্ক করে রাখছি।

এখন, একটা লুপের মাধ্যমেই আমরা পুরো সাইকেল টা খুজে পাইতে পারি। প্রথমে একটা Cycle Array রাখবো সাইকেলের নোড গুলা প্রিন্ট স্টোর করার জন্য।

        for(int v = cycle_end; v != cycle_start; v = parent[v]){
            cycle.push_back(v);
        }
এখানে সাইকেলের শেষ থেকে লুপ শুরু হইছে, যতক্ষন না সাইকেলে র শুরু তে না পৌছায় ততক্ষন লুপ চলতে থাকবে । প্রত্যেকবার ঐ নোডের প্যারেন্ট দ্বারা লুপ আপডেট করবো।

জিনিসটা আরো সুন্দর ভাবে বোঝা যেতে পারে, ধরি আমরা একটা নোড v তে আছি, এর প্যারেন্ট নোড এর প্যারেন্ট নোডে যাইতে v কে , V এর প্যারেন্ট দ্বারা আপডেট করবো।

Easy Implementation



Full Cycle Detection Implementation



Related Problems:

Round Trip
Round Trip II
Find Eventual Safe States (find nodes that are not in a cycle)
Cyclic Components

Wednesday, January 26, 2022

First Missing Positive Number

 41. First Missing Positive - Leetcode, Hard


সহজ প্রবলেম ডেসক্রিপশন, 

N সাইজের একটা Array দেয়া আছে, সব গুলাই Integer এবং Positive/Negative সব ধরনের নাম্বার ই থাকতে পারে।
ঐ নাম্বার গুলা থেকে সব থেকে ছোটো এবং পজিটিভ যে নাম্বার টা মিসিং সেটা আমাদেরকে বের করতে হবে।

যেমন,
N = 5, Array[5] = {1, 2, 3, 4, 5}
এখানে মিসিং পজিজিটিভ এবং ছোটো নাম্বার টা হচ্ছে 6
আবার,
N = 5, Array[5] = {0, -10, 1, 3, -20}
এখানে মিসিং পজিটিভ এবং ছোটো নাম্বার টা হচ্ছে ২


প্রবলেম সলুশ্যন আইডিয়া খুবই সোজা, ইলিমেন্ট গুলাকে সর্ট করে অথবা সেটে রেখে মিসিং নাম্বার বের করা যেতে পারে খুব সহজেই। তাহলে এটা Hard ক্যাটাগরির প্রবলেম কেনো ?

আমাদেরকে এই প্রবলেম টা এক্সট্রা কোনো মেমোরি ইউজ না করে অর্থ্যাত O(1) এবং লিনিয়ার অর্থ্যাত O(N) এ সলভ করতে হবে।


আইডিয়াঃ

প্রথম কেইজ,
সব থেকে ছোটো মিসিং পজিটিভ নাম্বার কত হইতে পারে ? 1 (One), Right ?
হ্যা,
এখন পুরো এরেতে যদি ১(এক) না থাকে তাহলে ১ ই আমাদের কাঙ্ক্ষিত রেজাল্ট।

দ্বিতীয় কেইজ,
সহজ চিন্তা, ১ থেকে N এর মধ্যে যদি রেজাল্ট এক্সিস্ট না করে তাহলে রেজাল্ট অবশ্যই N+1, উপরের প্রথম উদাহরন টা।
এই কেইজের হিসাব আলাদা ভাবে করার দরকার নাই, বোঝার সুবিধার্থে বললাম।

তৃতীয়  কেইজ,
আমাদের কাঙ্ক্ষিত রেজাল্ট সবসময় ১ থেকে N এর মধ্যে এক্সিস্ট করবে একটু চিন্তা করলেই বোঝা যাবে। অর্থ্যাত যেকোনো নেগেটিভ নাম্বার এবং N এর থেকে বড় নাম্বার গুলা কে আমরা ইগ্নোর করবো।

ইগ্নোর ব্যাপার টা আরেকটু ভালোভাবে বলি,
উপরের দ্বিতীয় উদাহরন টা খেয়াল করি,

    Index =  0     1   2  3   4
Array[5] = {0, -10, 1, 3, -20}

এখানে মিসিং পজিটিভ নাম্বার ২, যে নাম্বার গুলা আমাদের দরকার নাই অর্থ্যাৎ নেগেটিভ এবং N এর থেকে বড় ঐ নাম্বার 
গুলাকে আমরা 1 দিয়ে Replace করে দিবো।
আর হ্যা, Zero কেও 1 দ্বারা রিপ্লেস করে দিবো। 

তাহলে এখন Array টা দাঁড়ায়,
Array[5] = {1, 1, 1, 3, 1}

খেয়াল করলে দেখা যাবে এই Array তে ১ থেকে N এর বাইরে কোনো নাম্বার নাই, কারন আমরা আগেই বলছিলাম আমাদের রেজাল্ট ১ থেকে N এর মধ্যে এক্সিস্ট করবে, আর আমরা সেভাবেই আগাচ্ছি।

এখন এই Array তে ছোটো একটা Operation করবো, 
বর্তমান পজিশন যদি i হয়, তাহলে 
Index = Array[i] - 1; // এটা দিয়ে আমরা একটা আমরা নতুন একটা Index বানাইলাম, মাইনাস ১ করলাম কারন, আমাদের Array 0 based.

এখন Array[Index] এ যেই ভ্যালু আছে , সেটা যদি পজিটিভ হয় তাহলে সেটাকে নেগেটিভ করে দিবো, আর যদি আগেই নেগেটিভ করা থাকে তাহলে ইগ্নোর করবো ।
এইভাবে সব গুলা ভ্যালুকে এইভাবে মডিফিকেশন করার পর , প্রথম যে Index এর ভ্যলু পজিটিভ পাবো, সেই Index+1 ই হবে আমাদের কাঙ্ক্ষিত রেজাল্ট।

Lets Modify,
    Index =  0   1  2  3  4
Array[5] = {1, 1, 1, 3, 1}

i = 0,
Index = Array[0] - 1 = 1-1 = 0
Array[Index] = Array[0] = -1
New Array,
    Index =  0   1   2  3  4
Array[5] = {-1, 1, 1, 3, 1}

i = 1,
Index = Array[1] - 1 = 1-1 = 0
Array[Index] = Array[0] = -1 // already -1 , no need to change

New Array,
    Index =  0   1    2  3  4
Array[5] = {-1, 1, 1, 3, 1}


i = 2,
Index = Array[2] - 1 = 1-1 = 0
Array[Index] = Array[0] = -1 
// already -1 , no need to change

New Array,
    Index =  0   1   2  3  4
Array[5] = {-1, 1, 1, 3, 1}


i = 2,
Index = Array[2] - 1 = 1-1 = 0
Array[Index] = Array[0] = -1 
// already -1 , no need to change

New Array,
    Index =  0   1   2  3  4
Array[5] = {-1, 1, 1, 3, 1}


i = 3,
Index = Array[3] - 1 = 3-1 = 2
Array[Index] = Array[2] = -1 


New Array,
    Index =  0   1   2  3  4
Array[5] = {-1, 1, -1, 3, 1}

i = 4,
Index = Array[4] - 1 = 1-1 = 0
Array[Index] = Array[0] = -1 
// already -1 , no need to change

New Array,
    Index =  0   1   2  3  4
Array[5] = {-1, 1, -1, 3, 1}


So, we got our final Modify array,

    Index =  0   1   2  3  4
Array[5] = {-1, 1, -1, 3, 1}

এখানে প্রথম থেকে ১ নাম্বার Index এর ভ্যালু পজিটিভ, তাহলে ১+১ = ২ আমাদের মিসিং পজিটিভ নাম্বার।

এখনোও বুঝতে না পারলে কোড

Thursday, November 18, 2021

201. Bitwise AND of Numbers Range - Leetcode

 201. Bitwise AND of Numbers Range - Leetcode, Medium

প্রবলেম টা একবার পড়লেই বোঝা যাবে, দুইটা নাম্বার দেয়া থাকবে A এবং B।
A থেকে B এর মধ্যে যত গুলা নাম্বার আছে সবার AND(&) করে তাদের রেজাল্ট রিটার্ন করতে হবে।
ধরি A = 2, B  = 10
সুতরাং Ans = 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10 = 0

আমরা চাইলেই কিন্তু এইভাবে A থেকে B পর্যন্ত লুপ চালিয়ে এন্সার বের করতে পারি, কিন্তু এক্ষেত্রে সম্ভব না, কারন আমাদের রেঞ্জ হইতে 2*10^9 পর্যন্ত। যেটা অনেক বড় একটা সংখ্যা।


এখন আসি কিভাবে আমরা এই প্রবলেম টা খুব সহজে বিট ম্যানিপুলেশন দিয়ে করে ফেলতে পারি।

পাশের ছবিটার দিকে তাকাই, ১-২০ পর্যন্ত সব গুলা সংখ্যার বাইনারি রিপ্রেজেন্টেশন দেয়া আছে। আপাতত ধরি আমাদের রেঞ্জ [১২,১৫], এদের বাইনারি - 
12 = 1100
13 = 1101
14 = 1110
15 = 1111
আমরা বাইনারি AND(&) এর ক্ষেত্রে জানি, যদি দুইটা বিট ই 1 হয়, তাহলে তাদের AND(&) হবে 1, অন্যসব ক্ষেত্রে 0. এখন ১২ থেকে ১৫ পর্যন্ত আমরা যদি সব গুলা বিট এক এক করে AND(&) করতে থাকি ডান দিক থেকে তাহলে প্রথম পজিশনের রেজাল্ট হবে 0, তারপর 0, তারপর বাকি দুইটা হবে 1.



আরো সুন্দর মত দেখি,
12 = 1100
13 = 1101
14 = 1110
15 = 1111
------------
(&)= 1100

যদি কোনোভাবে যেকোনো কলামে আমরা দুইটা আলাদা বিট ই (০ এবং ১) পাই তাহলে বাকি সব গুলা কলামের রেজাল্ট হবে শুন্য(০),
কারন ০&১ = ০.

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

১১ থেকে ১৫ এর বাম দিকে দুইটা করে দিট বাদ দিলে বাকি দুইটা করে বিট গুলা সবই সেইম, তাইনা ? তাহলে কিন্তু আমাদেরকে আর একটা রেঞ্জের সব গুলা নাম্বার নিয়ে কাজ করা লাগবে না, শুধুমাত্র প্রথম এবং শেষ নাম্বার নিয়ে কাজ করলেই হচ্ছে।

তাহলে, আমরা একটা লুপ চালাবো যতক্ষন না প্রথম এবং শেষ[A and B] সেইম না হয়, এবং একই সাথে তাদের ডান দিক থেকে বিট বাদ দিতে থাকবো। বাদ দেয়া বিট গুলা AND(&) করলে আমরা শুন্য পাবো, কারন তারা সবাই ভিন্ন ভিন্ন বিট।

বাদ দেয়ার কাজ টা আমরা Right Shift দিয়ে করতে পারি । কোড দেখলে খুব সহজেই বোঝা যাবে।
এখানে লাস্টে আবার কেনো diff_bit দিয়ে Left_shift করলাম ? কারন আমাদেরকে ভিন্ন বিট গুলার জন্য যে কইটা ভিন্ন বিট পাইলাম, সে কইটা শুন্য এড করা লাগবে।



Monday, November 15, 2021

Some Basic Bit Manipulation Problems with hints

 461. Hamming Distance  (Try to figure out XOR and set bit Count)
136. Single Number (Two same numbers XOR is 0, means a^a = 0)
268. Missing Number (Same as before, a^b^b = a. It can be also solved by using binary search, Think)
191. Number of 1 Bits (Count number of set bit(1))
231. Power of Two (Think using bit manipulation and without bit manipulation, solve using both cases)
342Power of Four (Same as before, think about both cases)
78. Subsets (Each subset can be represented as a single bit)
1720. Decode XORed Array (Read the problem statement carefully)
1486. XOR Operation in an Array 
(Read the problem statement carefully)
1863. Sum of All Subset XOR Totals (Simple backtracking)
371. Sum of Two Integers (Think about carry of two values and sum with recursively)