Day 16: Sliding Window Technique

Day 16: Sliding Window Technique

Welcome to Day 16 of my 100 Days of DSA challenge! Today, I dived into the sliding window technique, solving problems that required optimizing solutions for contiguous subarrays and substrings. This method is an elegant way to reduce redundant computations and efficiently manage dynamic ranges within data.

Check out my GitHub repository for all the solutions and progress updates at: 100 Days of DSA

Let’s explore how it works through today’s challenges! 🚀


1. Maximum Sum Subarray of Size K

This program calculates the maximum sum of any subarray of size k using the sliding window technique. It first computes the sum of the initial window of size k, then slides the window across the array by adding the next element and removing the first element of the previous window. At each step, it updates the maximum sum if the current window sum is larger.

Code:

#include <iostream>
using namespace std;

int max_sum_subarray(int arr[], int n, int k) {
    if (n < k) {
        cout << "Invalid input: Array size is smaller than k." << endl;
        return -1;
    }

    // Calculate the sum of the first window of size k
    int max_sum = 0;
    for (int i = 0; i < k; i++) {
        max_sum += arr[i];
    }

    // Sliding window to calculate sum of remaining subarrays of size k
    int window_sum = max_sum;
    for (int i = k; i < n; i++) {
        window_sum += arr[i] - arr[i - k];  // Slide the window
        max_sum = max(max_sum, window_sum); // Update the maximum sum
    }

    return max_sum;
}

int main() {
    int arr[] = {2, 1, 5, 1, 3, 2};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k;
    cout << "Array: " << endl;
    for (int i = 0; i < n; i++) {
        cout << arr[i] << " ";
    }
    cout << endl;
    cout << "Enter the value of k: ";
    cin >> k;
    int result = max_sum_subarray(arr, n, k);
    if (result != -1) {
        cout << "Maximum sum of subarray of size " << k << " is: " << result << endl;
    }
    return 0;
}

Output:


2. Longest Substring Without Repeating Characters

This program finds the length of the longest substring without repeating characters using an array to track the last seen position of each character. It iterates through the string, updating the start of the current substring if a character is repeated within the current window. The array last_seen stores the last occurrence index of each character, and the maximum substring length is updated during each step.

Code:

#include <iostream>
#include <string>
using namespace std;

int long_substr_wo_repeating(string str) {
    int n = str.length();
    int max_length = 0;                     // Maximum length of substring
    int start = 0;                          // Starting index of the current substring
    int last_seen[256];                     // Array to store last seen positions of characters
    fill(last_seen, last_seen + 256, -1);   // Initialize all positions to -1

    for (int end = 0; end < n; end++) {
        char current_char = str[end];

        // If the character has been seen and is within the current window
        if (last_seen[current_char] >= start) {
            start = last_seen[current_char] + 1;
        }

        // Update the last seen index of the current character
        last_seen[current_char] = end;

        // Update the maximum length of the substring
        max_length = max(max_length, end - start + 1);
    }

    return max_length;
}

int main() {
    string str = "abcadabacd";
    cout << "String: " << str << endl;
    cout << "The length of the longest substring without repeating characters is: " << long_substr_wo_repeating(str) << endl;
    return 0;
}

Output:


3. Smallest Window in a String Containing All Characters of Another String

This program finds the smallest substring in a given string (str) that contains all characters of another string (pat). It uses two frequency arrays, one for the pattern and another for the sliding window in str, to track character counts. The sliding window expands to include characters, and once all characters from pat are included, it attempts to shrink the window to find the smallest valid substring.

Code:

#include <iostream>
#include <string>
#include <climits>
using namespace std;

string smallest_window(string str, string pat) {
    int str_len = str.length();
    int pat_len = pat.length();

    if (str_len < pat_len) {
        return ""; // If the pattern is longer than the string, no solution exists.
    }

    // Frequency arrays for pattern and sliding window
    int pat_count[256] = {0};
    int window_count[256] = {0};

    // Count the frequency of characters in the pattern
    for (int i = 0; i < pat_len; i++) {
        pat_count[pat[i]]++;
    }

    int start = 0, min_length = INT_MAX, start_index = -1;
    int count = 0; // Number of characters matched

    for (int end = 0; end < str_len; end++) {
        // Include current character in the window
        char current_char = str[end];
        window_count[current_char]++;

        // Check if the current character matches the frequency in the pattern
        if (pat_count[current_char] != 0 && window_count[current_char] <= pat_count[current_char]) {
            count++;
        }

        // If all characters are matched, try to shrink the window
        while (count == pat_len) {
            char start_char = str[start];

            // Update the minimum window size
            int window_size = end - start + 1;
            if (window_size < min_length) {
                min_length = window_size;
                start_index = start;
            }

            // Shrink the window from the left
            window_count[start_char]--;
            if (pat_count[start_char] != 0 && window_count[start_char] < pat_count[start_char]) {
                count--;
            }
            start++;
        }
    }

    // Return the smallest window or an empty string if no such window exists
    if (start_index == -1) {
        return "";
    }
    return str.substr(start_index, min_length);
}

int main() {
    string str = "aabcbcdbca";
    string pat = "abcd";

    string result = smallest_window(str, pat);
    if (result.empty()) {
        cout << "No such window exists" << endl;
    } else {
        cout << "Smallest window containing all characters is: " << result << endl;
    }
    return 0;
}

Output:


4. Find All Anagrams of a String in Another String

This program finds all substrings in a given string that are anagrams of a specified pattern. It does this by using a sliding window approach, where it maintains a window of the same size as the pattern and compares the frequency of characters in this window with the frequency of characters in the pattern. If the frequencies match, it identifies the current window as an anagram and prints the starting index. The window then slides one character at a time, and the process continues until the entire string is processed.

Code:

#include <iostream>
#include <string>
using namespace std;

// Function to find all anagrams of a string in another string
void anagrams(string str, string pat) {
    int str_len = str.length();
    int pat_len = pat.length();

    if (str_len < pat_len) {
        cout << "No anagrams found!" << endl;
        return;
    }

    // Frequency arrays for pattern and window
    int pat_count[256] = {0};
    int window_count[256] = {0};

    // Count frequency of characters in the pattern
    for (int i = 0; i < pat_len; i++) {
        pat_count[pat[i]]++;
    }

    // Initialize variables for the sliding window
    int start = 0;
    for (int end = 0; end < str_len; end++) {
        // Include the current character in the window
        window_count[str[end]]++;

        // If the window has reached the size of the pattern
        if (end - start + 1 == pat_len) {
            // Compare window with the pattern's frequency array
            bool is_anagram = true;
            for (int i = 0; i < 256; i++) {
                if (window_count[i] != pat_count[i]) {
                    is_anagram = false;
                    break;
                }
            }

            // If it is an anagram, print the starting index
            if (is_anagram) {
                cout << "Anagram found at index: " << start << endl;
            }

            // Slide the window by removing the character at the start
            window_count[str[start]]--;
            start++;
        }
    }
}

int main() {
    string str = "aaabaabaa";
    string pat = "aba";
    cout << "Anagrams of \"" << pat << "\" in \"" << str << "\":" << endl;
    anagrams(str, pat);
    return 0;
}

Output:


5. Maximum Number of Vowels in a Substring of Length K

This program calculates the maximum number of vowels in any substring of length k from a given string. It uses a sliding window approach to efficiently count the vowels in the current window of size k and updates the count as the window slides across the string. Initially, it counts the vowels in the first window, and as the window moves, it adjusts the count by removing the effect of the character leaving the window and adding the character entering the window. The program keeps track of the highest vowel count found and outputs that as the result.

Code:

#include <iostream>
#include <string>
using namespace std;

// Function to check if a character is a vowel
bool is_vowel(char c) {
    char lower_c = tolower(c);  // Convert to lowercase to handle both cases
    return lower_c == 'a' || lower_c == 'e' || lower_c == 'i' || lower_c == 'o' || lower_c == 'u';
}

// Function to find the maximum number of vowels in a substring of length k
int max_vowels(string str, int k) {
    int n = str.length();
    int maxVowels = 0;
    int currentVowels = 0;

    // First, count the vowels in the first window of size k
    for (int i = 0; i < k && i < n; i++) {
        if (is_vowel(str[i])) {
            currentVowels++;
        }
    }

    // Set the initial maxVowels to the count from the first window
    maxVowels = currentVowels;

    // Now slide the window through the rest of the string
    for (int i = k; i < n; i++) {
        // Remove the vowel count of the leftmost character of the window
        if (is_vowel(str[i - k])) {
            currentVowels--;
        }
        // Add the vowel count of the new character entering the window
        if (is_vowel(str[i])) {
            currentVowels++;
        }

        // Update maxVowels if currentVowels is greater
        maxVowels = max(maxVowels, currentVowels);
    }

    return maxVowels;
}

int main() {
    string str = "abcdeiouwaec";
    int k;
    cout << "String: " << str << endl;
    cout << "Enter value of k: ";
    cin >> k;
    int result = max_vowels(str, k);
    cout << "Maximum number of vowels in a substring of length " << k << ": " << result << endl;
    return 0;
}

Output:


Day 16 highlighted the power of the Sliding Window Technique in tackling problems with contiguous subarrays and substrings. By adjusting the window dynamically, we can efficiently handle large datasets, saving both time and space. Today’s problems reinforced how this technique streamlines solutions, and I'm excited to apply it to even more complex challenges ahead! 🚀