Algorithm Techniques: A Comprehensive Guide

Hamidul Islam

Hamidul Islam

@Hamidul Islam

Algorithm Techniques: A Comprehensive Guide
Algorithm Techniques: A Comprehensive Guide

1. Sliding Window Technique

When to Use?

  • Optimizing subarray or substring problems
  • Finding continuous sequences
  • Solving problems with linear time complexity

Techniques

  • Fixed Sliding Window
  • Dynamic Sliding Window
def fixed_sliding_window(arr, k):
    window_sum = sum(arr[:k])
    max_sum = window_sum
 
    for i in range(k, len(arr)):
        window_sum = window_sum - arr[i-k] + arr[i]
        max_sum = max(max_sum, window_sum)
 
    return max_sum
 
def dynamic_sliding_window(arr, target):
    left = total = 0
    min_length = float('inf')
 
    for right in range(len(arr)):
        total += arr[right]
 
        while total >= target:
            min_length = min(min_length, right - left + 1)
            total -= arr[left]
            left += 1
 
    return min_length if min_length != float('inf') else 0

LeetCode Problems

  • Maximum Subarray Sum
  • Longest Substring Without Repeating Characters
  • Minimum Window Substring

2. Two Pointers Technique

When to Use?

  • Searching pairs in sorted arrays
  • Reversing arrays/linked lists
  • Detecting cycles
  • Comparing sequences efficiently

Implementation

def pair_with_target_sum(arr, target):
    left, right = 0, len(arr) - 1
 
    while left < right:
        current_sum = arr[left] + arr[right]
 
        if current_sum == target:
            return [left, right]
 
        if current_sum < target:
            left += 1
        else:
            right -= 1
 
    return []

LeetCode Problems

  • Two Sum II
  • Container With Most Water
  • 3Sum

3. Fast and Slow Pointers

When to Use?

  • Detecting cycles in linked lists
  • Finding midpoint of structures
  • Identifying repeated elements

Implementation

def has_cycle(head):
    slow = fast = head
 
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
 
        if slow == fast:
            return True
 
    return False
 
def find_cycle_start(head):
    slow = fast = head
 
    while fast and fast.next:
        slow = slow.next
        fast = fast.next.next
 
        if slow == fast:
            slow = head
            while slow != fast:
                slow = slow.next
                fast = fast.next
 
            return slow
 
    return None

LeetCode Problems

  • Linked List Cycle
  • Middle of the Linked List
  • Palindrome Linked List

4. In-Place Linked List Reversal

When to Use?

  • Reversing linked list order
  • Memory-efficient list transformations

Implementation

def reverse_linked_list(head):
    prev = None
    current = head
 
    while current:
        next_node = current.next
        current.next = prev
        prev = current
        current = next_node
 
    return prev

LeetCode Problems

  • Reverse Linked List
  • Reverse Linked List II
  • Rotate List

When to Use?

  • Searching sorted arrays
  • Finding insertion points
  • Handling ordered collections

Implementation

def binary_search(arr, target):
    left, right = 0, len(arr) - 1
 
    while left <= right:
        mid = (left + right) // 2
 
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
 
    return -1

LeetCode Problems

  • Binary Search
  • Search in Rotated Sorted Array
  • First Bad Version

6. Top K Elements

When to Use?

  • Finding largest/smallest k elements
  • Priority queue problems
  • Heap-based solutions

Implementation

import heapq
 
def top_k_frequent(nums, k):
    frequency = {}
    for num in nums:
        frequency[num] = frequency.get(num, 0) + 1
 
    return heapq.nlargest(k, frequency.keys(), key=frequency.get)

LeetCode Problems

  • Top K Frequent Elements
  • K Closest Points to Origin
  • Kth Largest Element

7. Binary Tree Traversal

Techniques

  • Depth-First Search (DFS)
  • Breadth-First Search (BFS)

Implementation

def inorder_traversal(root):
    result = []
 
    def traverse(node):
        if not node:
            return
 
        traverse(node.left)
        result.append(node.val)
        traverse(node.right)
 
    traverse(root)
    return result

LeetCode Problems

  • Binary Tree Inorder Traversal
  • Maximum Depth of Binary Tree
  • Symmetric Tree

8. Graph and Matrices

Techniques

  • DFS/BFS Traversal
  • Path Finding
  • Connected Components

Implementation

def num_islands(grid):
    if not grid:
        return 0
 
    rows, cols = len(grid), len(grid[0])
    islands = 0
 
    def dfs(r, c):
        if r < 0 or r >= rows or c < 0 or c >= cols or grid[r][c] != '1':
            return
 
        grid[r][c] = '0'
        dfs(r+1, c)
        dfs(r-1, c)
        dfs(r, c+1)
        dfs(r, c-1)
 
    for r in range(rows):
        for c in range(cols):
            if grid[r][c] == '1':
                dfs(r, c)
                islands += 1
 
    return islands

LeetCode Problems

  • Number of Islands
  • Max Area of Island
  • Flood Fill

9. Backtracking

When to Use?

  • Generating combinations
  • Solving constraint satisfaction problems
  • Exploring all possible solutions

Implementation

def generate_parentheses(n):
    result = []
 
    def backtrack(open_count, close_count, current):
        if len(current) == 2 * n:
            result.append(current)
            return
 
        if open_count < n:
            backtrack(open_count + 1, close_count, current + "(")
 
        if close_count < open_count:
            backtrack(open_count, close_count + 1, current + ")")
 
    backtrack(0, 0, "")
    return result

LeetCode Problems

  • Generate Parentheses
  • Combination Sum
  • Subsets

10. Dynamic Programming

Techniques

  • Memoization
  • Tabulation
  • State Reduction

Implementation

def fibonacci(n):
    if n <= 1:
        return n
 
    dp = [0] * (n + 1)
    dp[1] = 1
 
    for i in range(2, n + 1):
        dp[i] = dp[i-1] + dp[i-2]
 
    return dp[n]

LeetCode Problems

  • Fibonacci Number
  • Climbing Stairs
  • Maximum Subarray

11. Bit Manipulation

Techniques

  • Bitwise operations
  • XOR properties
  • Bit counting

Implementation

def single_number(nums):
    result = 0
    for num in nums:
        result ^= num
    return result

LeetCode Problems

  • Single Number
  • Number of 1 Bits
  • Reverse Bits

12. Overlapping Intervals

Techniques

  • Sorting intervals
  • Merge intervals
  • Finding conflicts

Implementation

def merge_intervals(intervals):
    intervals.sort(key=lambda x: x[0])
    merged = []
 
    for interval in intervals:
        if not merged or interval[0] > merged[-1][1]:
            merged.append(interval)
        else:
            merged[-1][1] = max(merged[-1][1], interval[1])
 
    return merged

LeetCode Problems

  • Merge Intervals
  • Insert Interval
  • Meeting Rooms

13. Monotonic Stack

Techniques

  • Next Greater/Smaller Element
  • Maintaining increasing/decreasing stacks

Implementation

def next_greater_elements(nums):
    n = len(nums)
    result = [-1] * n
    stack = []
 
    for i in range(2 * n):
        while stack and nums[stack[-1]] < nums[i % n]:
            result[stack.pop()] = nums[i % n]
 
        if i < n:
            stack.append(i)
 
    return result

LeetCode Problems

  • Next Greater Element I
  • Daily Temperatures
  • Remove K Digits

14. Prefix Sum

Techniques

  • Range sum queries
  • Cumulative calculations
  • Quick interval computations

Implementation

def subarray_sum(nums, k):
    count = 0
    prefix_sum = 0
    sum_counts = {0: 1}
 
    for num in nums:
        prefix_sum += num
 
        if prefix_sum - k in sum_counts:
            count += sum_counts[prefix_sum - k]
 
        sum_counts[prefix_sum] = sum_counts.get(prefix_sum, 0) + 1
 
    return count

LeetCode Problems

  • Subarray Sum Equals K
  • Range Sum Query
  • Product of Array Except Self

Conclusion

Master these algorithm techniques to solve complex computational problems efficiently and elegantly.