0% found this document useful (0 votes)
9 views15 pages

14 Pattern

The document outlines various algorithmic patterns used in programming, including Sliding Window, Two Pointers, Fast and Slow Pointers, Merge Intervals, Cyclic Sort, In-place Reversal of a Linked List, Tree BFS, and Tree DFS. Each pattern is described with its concept, how to identify it, and example problems implemented in C++. The examples are provided in C++ code with explanations to illustrate the application of each pattern.

Uploaded by

avoid ricky
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views15 pages

14 Pattern

The document outlines various algorithmic patterns used in programming, including Sliding Window, Two Pointers, Fast and Slow Pointers, Merge Intervals, Cyclic Sort, In-place Reversal of a Linked List, Tree BFS, and Tree DFS. Each pattern is described with its concept, how to identify it, and example problems implemented in C++. The examples are provided in C++ code with explanations to illustrate the application of each pattern.

Uploaded by

avoid ricky
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

1.

Sliding Window

Concept: The Sliding Window pattern is used to perform operations on a specific window size
of a given array or linked list. The window slides over the data structure from the beginning to
the end.

How to Identify:

• The input is a linear data structure (array, string, linked list).


• The problem requires finding the longest/shortest substring, subarray, or desired value.

Example Problem: Maximum Sum Subarray of Size ‘K’

python
Copy code
def max_subarray_sum(arr, k):
max_sum, window_sum = 0, 0
window_start = 0

for window_end in range(len(arr)):


window_sum += arr[window_end]
if window_end >= k - 1:
max_sum = max(max_sum, window_sum)
window_sum -= arr[window_start]
window_start += 1

return max_sum

# Test
print(max_subarray_sum([2, 1, 5, 1, 3, 2], 3)) # Output: 9

2. Two Pointers

Concept: Two pointers iterate through the data structure in tandem until one or both of the
pointers hit a certain condition. This is useful for problems involving pairs or subarrays in a
sorted array.

How to Identify:

• Problems with sorted arrays or linked lists.


• Problems asking to find a pair, triplet, or subarray that meets certain criteria.

Example Problem: Squaring a Sorted Array

python
Copy code
def square_sorted_array(arr):
n = len(arr)
squares = [0] * n
left, right = 0, n - 1
highest_square_index = n - 1

while left <= right:


left_square = arr[left] ** 2
right_square = arr[right] ** 2
if left_square > right_square:
squares[highest_square_index] = left_square
left += 1
else:
squares[highest_square_index] = right_square
right -= 1
highest_square_index -= 1

return squares

# Test
print(square_sorted_array([-2, -1, 0, 2, 3])) # Output: [0, 1, 4,
4o
use c++ and comments
ChatGPT

Sure! Let's go through each pattern with example problems in C++ and detailed comments.

1. Sliding Window

Example Problem: Maximum Sum Subarray of Size ‘K’

cpp
Copy code
#include <iostream>
#include <vector>
#include <algorithm>

int maxSubarraySum(const std::vector<int>& arr, int k) {


int maxSum = 0, windowSum = 0;
int windowStart = 0;

// Traverse the array with the window end pointer


for (int windowEnd = 0; windowEnd < arr.size(); ++windowEnd) {
windowSum += arr[windowEnd]; // Add the next element to the window
// Check if we have hit the required window size
if (windowEnd >= k - 1) {
maxSum = std::max(maxSum, windowSum); // Update the maximum sum
windowSum -= arr[windowStart]; // Slide the window ahead
++windowStart; // Slide the window start ahead
}
}
return maxSum;
}

int main() {
std::vector<int> arr = {2, 1, 5, 1, 3, 2};
int k = 3;
std::cout << "Maximum sum of a subarray of size " << k << " is " <<
maxSubarraySum(arr, k) << std::endl;
return 0;
}

2. Two Pointers

Example Problem: Squaring a Sorted Array

cpp
Copy code
#include <iostream>
#include <vector>

std::vector<int> squareSortedArray(const std::vector<int>& arr) {


int n = arr.size();
std::vector<int> squares(n);
int left = 0, right = n - 1;
int highestSquareIndex = n - 1;

// Traverse the array from both ends


while (left <= right) {
4o
with concepts and how to identify
ChatGPT

Sure, let's start with a brief explanation of each pattern along with how to identify it. Then we'll
look at the C++ code for each pattern.

1. Sliding Window

Concept: The Sliding Window pattern is used to perform operations on a specific window size
of a given array or linked list. The window slides over the data structure from the beginning to
the end, adjusting its size or content according to the problem requirements.

How to Identify:

• The problem involves a linear data structure (array, string, linked list).
• You need to find the longest/shortest substring, subarray, or a desired value.

Example Problem: Maximum Sum Subarray of Size ‘K’

cpp
Copy code
#include <iostream>
#include <vector>
#include <algorithm>

int maxSubarraySum(const std::vector<int>& arr, int k) {


int maxSum = 0, windowSum = 0;
int windowStart = 0;
// Traverse the array with the window end pointer
for (int windowEnd = 0; windowEnd < arr.size(); ++windowEnd) {
windowSum += arr[windowEnd]; // Add the next element to the window
// Check if we have hit the required window size
if (windowEnd >= k - 1) {
maxSum = std::max(maxSum, windowSum); // Update the maximum sum
windowSum -= arr[windowStart]; // Slide the window ahead
++windowStart; // Slide the window start ahead
}
}
return maxSum;
}

int main() {
std::vector<int> arr = {2, 1, 5, 1, 3, 2};
int k = 3;
std::cout << "Maximum sum of a subarray of size " << k << " is " <<
maxSubarraySum(arr, k) << std::endl;
return 0;
}

2. Two Pointers

Concept: Two pointers iterate through the data structure in tandem until one or both of the
pointers hit a certain condition. This is useful for problems involving pairs or subarrays in a
sorted array.

How to Identify:

• Problems with sorted arrays or linked lists.


• Problems asking to find a pair, triplet, or subarray that meets certain criteria.

Example Problem: Squaring a Sorted Array

cpp
Copy code
#include <iostream>
#include <vector>

std::vector<int> squareSortedArray(const std::vector<int>& arr) {


int n = arr.size();
std::vector<int> squares(n);
int left = 0, right = n - 1;
int highestSquareIndex = n - 1;

// Traverse the array from both ends


while (left <= right) {
int leftSquare = arr[left] * arr[left];
int rightSquare = arr[right] * arr[right];
if (leftSquare > rightSquare) {
squares[highestSquareIndex--] = leftSquare;
++left;
} else {
squares[highestSquareIndex--] = rightSquare;
--right;
}
}
return squares;
}

int main() {
std::vector<int> arr = {-2, -1, 0, 2, 3};
std::vector<int> result = squareSortedArray(arr);
std::cout << "Squared sorted array: ";
for (int num : result) {
std::cout << num << " ";
}
std::cout << std::endl;
return 0;
}

3. Fast and Slow Pointers

Concept: Also known as the Hare and Tortoise algorithm, this approach uses two pointers
moving at different speeds. It is useful for detecting cycles in linked lists or arrays.

How to Identify:

• The problem deals with a loop in a linked list or array.


• You need to find the position of a certain element or the overall length of the linked list.

Example Problem: Linked List Cycle

cpp
Copy code
#include <iostream>

class ListNode {
public:
int value;
ListNode *next;
ListNode(int val) : value(val), next(nullptr) {}
};

bool hasCycle(ListNode *head) {


ListNode *slow = head, *fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next; // Move slow pointer one step
fast = fast->next->next; // Move fast pointer two steps
if (slow == fast) { // Cycle detected
return true;
}
}
return false;
}
int main() {
ListNode *head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
head->next->next->next = head; // Create a cycle for testing

if (hasCycle(head)) {
std::cout << "Linked list has a cycle." << std::endl;
} else {
std::cout << "Linked list does not have a cycle." << std::endl;
}

return 0;
}

4. Merge Intervals

Concept: The Merge Intervals pattern deals with overlapping intervals, where you either need to
find overlapping intervals or merge them if they overlap.

How to Identify:

• The problem involves intervals.


• You are asked to produce a list with only mutually exclusive intervals.

Example Problem: Merge Intervals

cpp
Copy code
#include <iostream>
#include <vector>
#include <algorithm>

struct Interval {
int start;
int end;
Interval(int s, int e) : start(s), end(e) {}
};

std::vector<Interval> mergeIntervals(std::vector<Interval>& intervals) {


if (intervals.empty()) return intervals;

// Sort intervals by their start time


std::sort(intervals.begin(), intervals.end(), [](Interval a, Interval b)
{
return a.start < b.start;
});

std::vector<Interval> merged;
merged.push_back(intervals[0]);

for (int i = 1; i < intervals.size(); ++i) {


if (merged.back().end >= intervals[i].start) {
merged.back().end = std::max(merged.back().end,
intervals[i].end); // Merge overlapping intervals
} else {
merged.push_back(intervals[i]);
}
}

return merged;
}

int main() {
std::vector<Interval> intervals = { {1, 3}, {2, 6}, {8, 10}, {15, 18} };
std::vector<Interval> result = mergeIntervals(intervals);

std::cout << "Merged intervals: ";


for (const Interval& interval : result) {
std::cout << "[" << interval.start << ", " << interval.end << "] ";
}
std::cout << std::endl;

return 0;
}

5. Cyclic Sort

Concept: This pattern is useful for problems involving arrays containing numbers in a given
range. It sorts the array by placing each number in its correct position through swapping.

How to Identify:

• The problem involves a sorted array with numbers in a given range.


• The problem asks to find the missing/duplicate/smallest number in a sorted/rotated array.

Example Problem: Find the Missing Number

cpp
Copy code
#include <iostream>
#include <vector>

int findMissingNumber(std::vector<int>& nums) {


int i = 0;
while (i < nums.size()) {
if (nums[i] < nums.size() && nums[i] != nums[nums[i]]) {
std::swap(nums[i], nums[nums[i]]);
} else {
++i;
}
}

for (int i = 0; i < nums.size(); ++i) {


if (nums[i] != i) {
return i;
}
}

return nums.size();
}

int main() {
std::vector<int> nums = {3, 1, 0};
std::cout << "Missing number: " << findMissingNumber(nums) << std::endl;
return 0;
}

These examples should help you understand the concepts, identification, and implementation of
each pattern in C++. If you need more examples or further explanations, feel free to ask!

6. In-place Reversal of a Linked List

Concept: This pattern involves reversing the nodes of a linked list in place, often within a
specified range.

How to Identify:

• The problem asks to reverse a part of a linked list or the entire list.

Example Problem: Reverse a Linked List

cpp
Copy code
#include <iostream>

class ListNode {
public:
int value;
ListNode *next;
ListNode(int val) : value(val), next(nullptr) {}
};

ListNode* reverseLinkedList(ListNode* head) {


ListNode* prev = nullptr;
ListNode* current = head;
while (current != nullptr) {
ListNode* nextNode = current->next; // Temporarily store the next
node
current->next = prev; // Reverse the current node
prev = current; // Move the prev pointer forward
current = nextNode; // Move the current pointer
forward
}
return prev;
}

int main() {
ListNode* head = new ListNode(1);
head->next = new ListNode(2);
head->next->next = new ListNode(3);
head->next->next->next = new ListNode(4);
head->next->next->next->next = new ListNode(5);

ListNode* result = reverseLinkedList(head);


std::cout << "Reversed Linked List: ";
while (result != nullptr) {
std::cout << result->value << " ";
result = result->next;
}
std::cout << std::endl;

return 0;
}

7. Tree BFS (Breadth-First Search)

Concept: Tree BFS involves traversing the tree level by level. It is implemented using a queue.

How to Identify:

• The problem requires traversing a tree level by level or finding the shortest path in an
unweighted graph.

Example Problem: Level Order Traversal

cpp
Copy code
#include <iostream>
#include <vector>
#include <queue>

class TreeNode {
public:
int value;
TreeNode *left, *right;
TreeNode(int val) : value(val), left(nullptr), right(nullptr) {}
};

std::vector<std::vector<int>> levelOrderTraversal(TreeNode* root) {


std::vector<std::vector<int>> result;
if (root == nullptr) return result;

std::queue<TreeNode*> queue;
queue.push(root);

while (!queue.empty()) {
int levelSize = queue.size();
std::vector<int> currentLevel;
for (int i = 0; i < levelSize; ++i) {
TreeNode* currentNode = queue.front();
queue.pop();
currentLevel.push_back(currentNode->value);
if (currentNode->left != nullptr) {
queue.push(currentNode->left);
}
if (currentNode->right != nullptr) {
queue.push(currentNode->right);
}
}
result.push_back(currentLevel);
}

return result;
}

int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);

std::vector<std::vector<int>> result = levelOrderTraversal(root);


std::cout << "Level Order Traversal: ";
for (const auto& level : result) {
for (int val : level) {
std::cout << val << " ";
}
std::cout << std::endl;
}

return 0;
}

8. Tree DFS (Depth-First Search)

Concept: Tree DFS involves traversing the tree depth-wise. This can be implemented using
recursion or a stack.

How to Identify:

• The problem requires visiting all nodes of a tree.


• The problem can be solved by traversing the tree in pre-order, in-order, or post-order.

Example Problem: Pre-order Traversal

cpp
Copy code
#include <iostream>
#include <vector>

class TreeNode {
public:
int value;
TreeNode *left, *right;
TreeNode(int val) : value(val), left(nullptr), right(nullptr) {}
};

void preOrderTraversal(TreeNode* root, std::vector<int>& result) {


if (root == nullptr) return;
result.push_back(root->value); // Visit the root node
preOrderTraversal(root->left, result); // Traverse the left subtree
preOrderTraversal(root->right, result); // Traverse the right subtree
}

int main() {
TreeNode* root = new TreeNode(1);
root->left = new TreeNode(2);
root->right = new TreeNode(3);
root->left->left = new TreeNode(4);
root->left->right = new TreeNode(5);

std::vector<int> result;
preOrderTraversal(root, result);
std::cout << "Pre-order Traversal: ";
for (int val : result) {
std::cout << val << " ";
}
std::cout << std::endl;

return 0;
}

9. Two Heaps

Concept: Two Heaps pattern involves maintaining two heaps (a max-heap and a min-heap) to
keep track of the median or other statistics dynamically.

How to Identify:

• The problem involves finding the median or other statistics in a dynamic data stream.

Example Problem: Find the Median of a Number Stream

cpp
Copy code
#include <iostream>
#include <queue>

class MedianOfAStream {
private:
std::priority_queue<int> maxHeap; // Containing the first half of
numbers
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;
// Containing the second half of numbers

public:
void insertNum(int num) {
if (maxHeap.empty() || num <= maxHeap.top()) {
maxHeap.push(num);
} else {
minHeap.push(num);
}

// Balance the heaps


if (maxHeap.size() > minHeap.size() + 1) {
minHeap.push(maxHeap.top());
maxHeap.pop();
} else if (minHeap.size() > maxHeap.size()) {
maxHeap.push(minHeap.top());
minHeap.pop();
}
}

double findMedian() {
if (maxHeap.size() == minHeap.size()) {
return (maxHeap.top() + minHeap.top()) / 2.0;
}
return maxHeap.top();
}
};

int main() {
MedianOfAStream medianFinder;
medianFinder.insertNum(1);
medianFinder.insertNum(2);
std::cout << "The median is: " << medianFinder.findMedian() << std::endl;
medianFinder.insertNum(3);
std::cout << "The median is: " << medianFinder.findMedian() << std::endl;

return 0;
}

10. Subsets

Concept: The Subsets pattern involves generating all possible subsets of a given set.

How to Identify:

• The problem asks for all subsets, combinations, or permutations of a set.

Example Problem: Generate All Subsets

cpp
Copy code
#include <iostream>
#include <vector>

void generateSubsets(const std::vector<int>& nums, int index,


std::vector<int>& current, std::vector<std::vector<int>>& result) {
if (index == nums.size()) {
result.push_back(current);
return;
}
// Exclude the current element
generateSubsets(nums, index + 1, current, result);

// Include the current element


current.push_back(nums[index]);
generateSubsets(nums, index + 1, current, result);
current.pop_back(); // Backtrack
}

std::vector<std::vector<int>> subsets(const std::vector<int>& nums) {


std::vector<std::vector<int>> result;
std::vector<int> current;
generateSubsets(nums, 0, current, result);
return result;
}

int main() {
std::vector<int> nums = {1, 2, 3};
std::vector<std::vector<int>> result = subsets(nums);

std::cout << "Subsets: " << std::endl;


for (const auto& subset : result) {
std::cout << "[";
for (int num : subset) {
std::cout << num << " ";
}
std::cout << "]" << std::endl;
}

return 0;
}

11. Modified Binary Search

Concept: Modified Binary Search involves variations of binary search to solve problems in a
sorted array or matrix.

How to Identify:

• The problem involves a sorted array or matrix.


• The problem requires searching for an element or finding an element with specific
properties.

Example Problem: Find an Element in a Rotated Array

cpp
Copy code
#include <iostream>
#include <vector>

int searchRotatedArray(const std::vector<int>& nums, int target) {


int left = 0, right = nums.size() - 1;
while (left <= right) {
int mid = left + (right - left)
4o
continue
ChatGPT
cpp
Copy code
#include <iostream>
#include <vector>

int searchRotatedArray(const std::vector<int>& nums, int target) {


int left = 0, right = nums.size() - 1;

while (left <= right) {


int mid = left + (right - left) / 2;

if (nums[mid] == target) {
return mid; // Element found
}

// Check if the left half is sorted


if (nums[left] <= nums[mid]) {
if (target >= nums[left] && target < nums[mid]) {
right = mid - 1; // Search in the left half
} else {
left = mid + 1; // Search in the right half
}
} else {
// Right half is sorted
if (target > nums[mid] && target <= nums[right]) {
left = mid + 1; // Search in the right half
} else {
right = mid - 1; // Search in the left half
}
}
}

return -1; // Element not found


}

int main() {
std::vector<int> nums = {4, 5, 6, 7, 0, 1, 2};
int target = 0;
int index = searchRotatedArray(nums, target);

if (index != -1) {
std::cout << "Element found at index: " << index << std::endl;
} else {
std::cout << "Element not found" << std::endl;
}

return 0;
}
12. Top K Elements

Concept: The Top K Elements pattern involves finding the top K largest or smallest elements in
a collection. This is often solved using a heap.

How to Identify:

• The problem asks for the top K largest or smallest elements.


• The problem involves frequent insertions and deletions while maintaining the top K
elements.

Example Problem: Find the Top K Largest Numbers

cpp
Copy code
#include <iostream>
#include <vector>
#include <queue>

std::vector<int> findTopKLargestNumbers(const std::vector<int>& nums, int k)


{
std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;

for (int num : nums) {


minHeap.push(num);
if (minHeap.size() > k) {
minHeap.pop();
}
}

std::vector<int> topKElements;
while (!minHeap.empty()) {
topKElements.push_back(minHeap.top());
minHeap.pop();
}

return topKElements;
}

int main() {
std::vector<int> nums = {3, 1, 5, 12, 2, 11};
int k = 3;
std::vector<int> result = findTopKLargestNumbers(nums, k);

std::cout << "Top " << k << " largest numbers are: ";
for (int num : result) {
std::cout << num << " ";
}
std::cout << std::endl;

return 0;
}

You might also like