ভূমিকা
Sliding Window হলো একটি শক্তিশালী algorithmic technique যা array বা string-এর উপর contiguous subarray বা substring নিয়ে কাজ করে। এই technique-এ একটি window ধীরে ধীরে সরিয়ে নেওয়া হয়, এবং nested loop ব্যবহার না করে O(n) সময়ে সমস্যা সমাধান করা যায়।
সমস্যা ১: Maximum Sum Subarray of Size K (নির্দিষ্ট আকারের সর্বোচ্চ যোগফলের Subarray)
সমস্যার বিবরণ
একটি integer array nums এবং একটি positive integer k দেওয়া আছে। k আকারের সব subarray-এর মধ্যে সর্বোচ্চ যোগফল বের করতে হবে।
উদাহরণ:
- Input:
nums = [2, 1, 5, 1, 3, 2],k = 3 - Output:
9 - কারণ:
[5, 1, 3]এর যোগফল = 9, যা সবচেয়ে বেশি - Input:
nums = [2, 3, 4, 1, 5],k = 2 - Output:
7 - কারণ:
[3, 4]এর যোগফল = 7
চিন্তার পদ্ধতি
Fixed-size Sliding Window ব্যবহার করব। প্রথমে প্রথম kটি element-এর যোগফল বের করব। তারপর window সরানোর সময় নতুন element যোগ করব এবং পুরনো element বাদ দেব। প্রতিটি step-এ maximum track করব।
সমাধান (Java)
public class MaxSumSubarrayOfSizeK {
public int maxSum(int[] nums, int k) {
if (nums == null || nums.length < k) return -1;
int windowSum = 0;
int maxSum = 0;
// প্রথম window-এর যোগফল বের করি
for (int i = 0; i < k; i++) {
windowSum += nums[i];
}
maxSum = windowSum;
// Window slide করি — নতুন element যোগ, পুরনো element বাদ
for (int i = k; i < nums.length; i++) {
windowSum += nums[i] - nums[i - k]; // right থেকে যোগ, left থেকে বাদ
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
public static void main(String[] args) {
MaxSumSubarrayOfSizeK solution = new MaxSumSubarrayOfSizeK();
System.out.println(solution.maxSum(new int[]{2, 1, 5, 1, 3, 2}, 3)); // Output: 9
System.out.println(solution.maxSum(new int[]{2, 3, 4, 1, 5}, 2)); // Output: 7
System.out.println(solution.maxSum(new int[]{-1, -2, -3, -4}, 2)); // Output: -3
}
}
সময় জটিলতা: O(n) | স্থান জটিলতা: O(1)
সমস্যা ২: Longest Substring with At Most K Distinct Characters
সমস্যার বিবরণ
একটি string s এবং একটি integer k দেওয়া আছে। সর্বোচ্চ kটি distinct character আছে এমন সবচেয়ে দীর্ঘ substring-এর দৈর্ঘ্য বের করতে হবে।
উদাহরণ:
- Input:
s = "eceba",k = 2 - Output:
3 - কারণ:
"ece"হলো সবচেয়ে দীর্ঘ substring যেখানে মাত্র 2টি distinct character (e,c) - Input:
s = "aa",k = 1 - Output:
2
চিন্তার পদ্ধতি
Variable-size Sliding Window এবং HashMap ব্যবহার করব। right pointer বাড়াবো এবং character frequency track করব। Window-এ distinct character-এর সংখ্যা k ছাড়িয়ে গেলে left pointer সরিয়ে window ছোট করব।
সমাধান (Java)
import java.util.HashMap;
import java.util.Map;
public class LongestSubstringKDistinct {
public int lengthOfLongestSubstringKDistinct(String s, int k) {
if (s == null || s.length() == 0 || k == 0) return 0;
Map<Character, Integer> charCount = new HashMap<>();
int left = 0;
int maxLength = 0;
for (int right = 0; right < s.length(); right++) {
char rightChar = s.charAt(right);
// Right character window-এ যোগ করি
charCount.put(rightChar, charCount.getOrDefault(rightChar, 0) + 1);
// Distinct character k-এর বেশি হলে left সরাই
while (charCount.size() > k) {
char leftChar = s.charAt(left);
charCount.put(leftChar, charCount.get(leftChar) - 1);
if (charCount.get(leftChar) == 0) {
charCount.remove(leftChar); // distinct character সরিয়ে দাও
}
left++;
}
// সর্বোচ্চ দৈর্ঘ্য আপডেট করি
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
}
public static void main(String[] args) {
LongestSubstringKDistinct solution = new LongestSubstringKDistinct();
System.out.println(solution.lengthOfLongestSubstringKDistinct("eceba", 2)); // Output: 3
System.out.println(solution.lengthOfLongestSubstringKDistinct("aa", 1)); // Output: 2
System.out.println(solution.lengthOfLongestSubstringKDistinct("aabbcc", 2)); // Output: 4
}
}
সময় জটিলতা: O(n) | স্থান জটিলতা: O(k)
সমস্যা ৩: Minimum Window Substring
সমস্যার বিবরণ
দুটি string s এবং t দেওয়া আছে। s-এর সবচেয়ে ছোট window (substring) খুঁজে বের করতে হবে যেটিতে t-এর সব character অন্তর্ভুক্ত থাকে। যদি কোনো valid window না থাকে তাহলে "" return করতে হবে।
উদাহরণ:
- Input:
s = "ADOBECODEBANC",t = "ABC" - Output:
"BANC" - কারণ:
"BANC"সবচেয়ে ছোট window যেখানেA,B,Cসবই আছে - Input:
s = "a",t = "a" - Output:
"a"
চিন্তার পদ্ধতি
Variable Sliding Window এবং দুটি HashMap ব্যবহার করব। t-এর character frequency রাখব। right বাড়িয়ে valid window তৈরি করব। Window valid হলে left সরিয়ে minimum খুঁজব।
সমাধান (Java)
import java.util.HashMap;
import java.util.Map;
public class MinimumWindowSubstring {
public String minWindow(String s, String t) {
if (s.length() < t.length()) return "";
// t-এর character frequency count
Map<Character, Integer> tCount = new HashMap<>();
for (char c : t.toCharArray()) {
tCount.put(c, tCount.getOrDefault(c, 0) + 1);
}
int required = tCount.size(); // t-তে unique character সংখ্যা
int formed = 0; // window-এ desired frequency-র character সংখ্যা
Map<Character, Integer> windowCount = new HashMap<>();
int left = 0;
int minLen = Integer.MAX_VALUE;
int minLeft = 0;
for (int right = 0; right < s.length(); right++) {
char c = s.charAt(right);
windowCount.put(c, windowCount.getOrDefault(c, 0) + 1);
// এই character-এর frequency t-এর মতো হয়েছে কিনা চেক করি
if (tCount.containsKey(c) && windowCount.get(c).intValue() == tCount.get(c).intValue()) {
formed++;
}
// Window valid — left সরিয়ে minimum খুঁজি
while (formed == required) {
if (right - left + 1 < minLen) {
minLen = right - left + 1;
minLeft = left;
}
char leftChar = s.charAt(left);
windowCount.put(leftChar, windowCount.get(leftChar) - 1);
if (tCount.containsKey(leftChar) && windowCount.get(leftChar) < tCount.get(leftChar)) {
formed--;
}
left++;
}
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(minLeft, minLeft + minLen);
}
public static void main(String[] args) {
MinimumWindowSubstring solution = new MinimumWindowSubstring();
System.out.println(solution.minWindow("ADOBECODEBANC", "ABC")); // Output: "BANC"
System.out.println(solution.minWindow("a", "a")); // Output: "a"
System.out.println(solution.minWindow("a", "b")); // Output: ""
}
}
সময় জটিলতা: O(|s| + |t|) | স্থান জটিলতা: O(|s| + |t|)
সমস্যা ৪: Fruits Into Baskets (At Most 2 Distinct Fruits)
সমস্যার বিবরণ
একটি integer array fruits দেওয়া আছে যেখানে fruits[i] হলো i-তম গাছে কোন ধরনের ফল আছে। দুটি basket নিয়ে একটানা গাছ থেকে ফল সংগ্রহ করতে হবে। প্রতিটি basket-এ শুধু একই ধরনের ফল রাখা যাবে। সর্বোচ্চ কতটি ফল সংগ্রহ করা যায় তা বের করতে হবে।
উদাহরণ:
- Input:
fruits = [1, 2, 1] - Output:
3(সব ফল নেওয়া যায়) - Input:
fruits = [0, 1, 2, 2] - Output:
3 - কারণ:
[1, 2, 2]— দুই ধরনের ফল (1 এবং 2) এবং সর্বোচ্চ 3টি
চিন্তার পদ্ধতি
এটি মূলত "At Most 2 Distinct Characters সহ সবচেয়ে দীর্ঘ Subarray" সমস্যা। Sliding Window এবং HashMap দিয়ে সর্বোচ্চ 2 ধরনের fruit রাখব।
সমাধান (Java)
import java.util.HashMap;
import java.util.Map;
public class FruitsIntoBaskets {
public int totalFruit(int[] fruits) {
Map<Integer, Integer> basket = new HashMap<>(); // fruit type -> count
int left = 0;
int maxFruits = 0;
for (int right = 0; right < fruits.length; right++) {
// Right fruit basket-এ রাখি
basket.put(fruits[right], basket.getOrDefault(fruits[right], 0) + 1);
// Basket-এ 2-এর বেশি type হলে left সরাই
while (basket.size() > 2) {
basket.put(fruits[left], basket.get(fruits[left]) - 1);
if (basket.get(fruits[left]) == 0) {
basket.remove(fruits[left]); // এই fruit type শেষ, basket থেকে বাদ
}
left++;
}
// সর্বোচ্চ ফলের সংখ্যা আপডেট
maxFruits = Math.max(maxFruits, right - left + 1);
}
return maxFruits;
}
public static void main(String[] args) {
FruitsIntoBaskets solution = new FruitsIntoBaskets();
System.out.println(solution.totalFruit(new int[]{1, 2, 1})); // Output: 3
System.out.println(solution.totalFruit(new int[]{0, 1, 2, 2})); // Output: 3
System.out.println(solution.totalFruit(new int[]{1, 2, 3, 2, 2})); // Output: 4
}
}
সময় জটিলতা: O(n) | স্থান জটিলতা: O(1) (basket-এ সর্বোচ্চ 3টি entry)
সমস্যা ৫: Longest Repeating Character Replacement
সমস্যার বিবরণ
একটি uppercase string s এবং integer k দেওয়া আছে। সর্বোচ্চ kটি character পরিবর্তন করে সবচেয়ে দীর্ঘ substring তৈরি করতে হবে যেখানে সব character একই। এই দীর্ঘতম substring-এর দৈর্ঘ্য বের করতে হবে।
উদাহরণ:
- Input:
s = "ABAB",k = 2 - Output:
4 - কারণ: 2টি
AবাBপরিবর্তন করলে সম্পূর্ণ string একই character হয় - Input:
s = "AABABBA",k = 1 - Output:
4 - কারণ: index 4 থেকে
"ABBA"তে 1টি পরিবর্তন করে"AAAA"বা"BBBB"পাওয়া যায়
চিন্তার পদ্ধতি
Sliding Window ব্যবহার করব। Window-এর সর্বোচ্চ frequency character track করব (maxFreq)। যদি window size - maxFreq > k হয় তাহলে আমাদের k-এর বেশি replacement দরকার — তখন left সরাতে হবে। Window কখনো ছোট হয় না, শুধু বড় বা সমান থাকে।
সমাধান (Java)
public class LongestRepeatingCharacterReplacement {
public int characterReplacement(String s, int k) {
int[] count = new int[26]; // প্রতিটি character-এর frequency
int left = 0;
int maxFreq = 0; // window-এর সবচেয়ে বেশি আসা character-এর frequency
int maxLength = 0;
for (int right = 0; right < s.length(); right++) {
int idx = s.charAt(right) - 'A';
count[idx]++;
// Window-এর সর্বোচ্চ frequency আপডেট করি
maxFreq = Math.max(maxFreq, count[idx]);
// Window valid কিনা চেক: (window size - maxFreq) <= k হলে valid
int windowSize = right - left + 1;
if (windowSize - maxFreq > k) {
// Window invalid — left সরাই
count[s.charAt(left) - 'A']--;
left++;
}
// Window size কখনো কমে না, তাই সর্বোচ্চ সবসময় বাড়তে থাকে
maxLength = Math.max(maxLength, right - left + 1);
}
return maxLength;
}
public static void main(String[] args) {
LongestRepeatingCharacterReplacement solution = new LongestRepeatingCharacterReplacement();
System.out.println(solution.characterReplacement("ABAB", 2)); // Output: 4
System.out.println(solution.characterReplacement("AABABBA", 1)); // Output: 4
System.out.println(solution.characterReplacement("AAAA", 2)); // Output: 4
System.out.println(solution.characterReplacement("ABCDE", 1)); // Output: 2
}
}
সময় জটিলতা: O(n) | স্থান জটিলতা: O(1)
সারসংক্ষেপ
| সমস্যা | Window Type | পদ্ধতি | সময় জটিলতা | স্থান জটিলতা |
|---|---|---|---|---|
| Max Sum Subarray of Size K | Fixed | Simple sliding sum | O(n) | O(1) |
| Longest Substring K Distinct | Variable | HashMap + shrink | O(n) | O(k) |
| Minimum Window Substring | Variable | Two HashMaps | O(n) | O(n) |
| Fruits Into Baskets | Variable | HashMap (≤2 types) | O(n) | O(1) |
| Longest Repeating Char Replacement | Variable | Count array + maxFreq | O(n) | O(1) |
Sliding Window-এর মূল সূত্র: window expand করো right দিয়ে, invalid হলে left সরিয়ে shrink করো। Fixed window-এ size সবসময় একই থাকে, আর variable window-এ condition অনুযায়ী size পরিবর্তন হয়। এই pattern রপ্ত করলে array ও string-এর বেশিরভাগ subarray/substring সমস্যা O(n)-এ সমাধান করা সম্ভব।