1. Opposite Ends Technique (left and right pointers)
Pattern
Initialization
Movement Rule
Use Case
Two Sum Sorted
left = 0, right = n-1
Move left if sum too small, right if too large
Find pair with target sum in sorted array
Palindrome Check
left = 0, right = n-1
Move both inward while characters match
Verify if string is palindrome
Container Most Water
left = 0, right = n-1
Move pointer with smaller height
Maximize area between two vertical lines
Reverse Array
left = 0, right = n-1
Swap and move both pointers inward
In-place array reversal
Example: Two sum in sorted array
function twoSum(numbers, target) { let left = 0; let right = numbers.length - 1; while (left < right) { const sum = numbers[left] + numbers[right]; if (sum === target) { return [left, right]; // or [left+1, right+1] for 1-indexed } else if (sum < target) { left++; // Need larger sum } else { right--; // Need smaller sum } } return [-1, -1]; // Not found}// Exampleconsole.log(twoSum([2, 7, 11, 15], 9)); // Output: [0, 1]
Example: Valid palindrome
function isPalindrome(s) { // Normalize: remove non-alphanumeric, lowercase s = s.toLowerCase().replace(/[^a-z0-9]/g, ''); let left = 0; let right = s.length - 1; while (left < right) { if (s[left] !== s[right]) { return false; } left++; right--; } return true;}// Exampleconsole.log(isPalindrome("A man, a plan, a canal: Panama")); // Output: true
2. Fast and Slow Pointers (Floyd's Cycle Detection)
Pattern
Speed Ratio
Detection
Application
Cycle Detection
Slow: +1, Fast: +2
Fast meets slow inside cycle
Detect loop in linked list (Floyd's algorithm)
Middle Element
Slow: +1, Fast: +2
When fast reaches end, slow at middle
Find middle node of linked list
Cycle Start
Reset one pointer to head after meeting
Both move at same speed, meet at cycle start
Find beginning of cycle in linked list
Happy Number
Fast computes twice per iteration
Converge to 1 or detect cycle
Determine if number is happy number
Example: Detect cycle in linked list
function hasCycle(head) { if (!head || !head.next) return false; let slow = head; let fast = head; while (fast && fast.next) { slow = slow.next; // Move 1 step fast = fast.next.next; // Move 2 steps if (slow === fast) { return true; // Cycle detected } } return false; // No cycle}
Example: Find middle of linked list
function middleNode(head) { let slow = head; let fast = head; while (fast && fast.next) { slow = slow.next; fast = fast.next.next; } // When fast reaches end, // slow is at middle return slow;}// For even length, returns // second middle node
Example: Find cycle start position
function detectCycle(head) { let slow = head, fast = head; // Phase 1: Detect if cycle exists while (fast && fast.next) { slow = slow.next; fast = fast.next.next; if (slow === fast) { // Phase 2: Find cycle start slow = head; while (slow !== fast) { slow = slow.next; fast = fast.next; } return slow; // Cycle start } } return null; // No cycle}
3. In-place Array Manipulation O(1) Space
Technique
Pointer Strategy
Space
Common Problem
Remove Duplicates
Slow tracks unique position, fast scans
O(1)
Remove duplicates from sorted array
Move Zeros
Slow marks non-zero position, fast scans
O(1)
Move all zeros to end of array
Remove Element
Write pointer for valid elements
O(1)
Remove all instances of target value
Squares Sorted Array
Compare from both ends, fill from back
O(n)
Square sorted array with negatives
Example: Remove duplicates from sorted array
function removeDuplicates(nums) { if (nums.length === 0) return 0; let slow = 0; // Position for next unique for (let fast = 1; fast < nums.length; fast++) { if (nums[fast] !== nums[slow]) { slow++; nums[slow] = nums[fast]; } } return slow + 1; // New length}// [1,1,2,2,3] -> [1,2,3,_,_], return 3
Example: Move zeros to end
function moveZeroes(nums) { let slow = 0; // Next non-zero position // Move all non-zeros forward for (let fast = 0; fast < nums.length; fast++) { if (nums[fast] !== 0) { nums[slow] = nums[fast]; slow++; } } // Fill remaining with zeros while (slow < nums.length) { nums[slow] = 0; slow++; }}
Example: Sorted squares with negative numbers
function sortedSquares(nums) { const n = nums.length; const result = new Array(n); let left = 0, right = n - 1; let pos = n - 1; // Fill from back while (left <= right) { const leftSquare = nums[left] * nums[left]; const rightSquare = nums[right] * nums[right]; if (leftSquare > rightSquare) { result[pos] = leftSquare; left++; } else { result[pos] = rightSquare; right--; } pos--; } return result;}// [-4,-1,0,3,10] -> [0,1,9,16,100]
4. Partitioning and Sorting Techniques
Algorithm
Invariant
Partitions
Use Case
Dutch National Flag
[0..low-1]=0, [high+1..n-1]=2
Three partitions: 0s, 1s, 2s
Sort array with 3 distinct values
QuickSort Partition
Elements < pivot left, > pivot right
Two partitions around pivot
Partition step in quicksort
Partition Array
Reorder by condition
Elements meeting condition first
Separate even/odd, positive/negative
Kth Element
QuickSelect partition
Eliminate half each iteration
Find kth largest/smallest element
Example: Dutch National Flag (Sort colors)
function sortColors(nums) { let low = 0; // Boundary for 0s let mid = 0; // Current element let high = nums.length - 1; // Boundary for 2s while (mid <= high) { if (nums[mid] === 0) { [nums[low], nums[mid]] = [nums[mid], nums[low]]; low++; mid++; } else if (nums[mid] === 1) { mid++; } else { // nums[mid] === 2 [nums[mid], nums[high]] = [nums[high], nums[mid]]; high--; // Don't increment mid - need to check swapped element } }}// [2,0,2,1,1,0] -> [0,0,1,1,2,2]
Example: Partition array around pivot
function partition(arr, low, high) { const pivot = arr[high]; let i = low - 1; // Index of smaller element for (let j = low; j < high; j++) { if (arr[j] < pivot) { i++; [arr[i], arr[j]] = [arr[j], arr[i]]; } } // Place pivot in correct position [arr[i + 1], arr[high]] = [arr[high], arr[i + 1]]; return i + 1; // Pivot index}
5. Collision Detection Patterns
Pattern
Scenario
Detection Method
Application
Meeting Point
Pointers converge from opposite ends
Check if pointers cross or meet
Binary search, palindrome validation
Circular Collision
Fast pointer catches slow in cycle
Fast laps slow pointer
Linked list cycle detection
Gap Closure
Distance between pointers decreases
Monitor pointer distance
Container with most water
Boundary Check
Pointers reach array bounds
Index validation before access
Prevent out-of-bounds errors
Example: Remove nth node from end of list
function removeNthFromEnd(head, n) { const dummy = { next: head }; let fast = dummy; let slow = dummy; // Move fast n+1 steps ahead for (let i = 0; i <= n; i++) { fast = fast.next; } // Move both until fast reaches end while (fast) { fast = fast.next; slow = slow.next; } // Remove nth node slow.next = slow.next.next; return dummy.next;}
6. Space Optimization O(1) Complexity
Technique
Space Saved
Trade-off
Example
In-place Modification
O(n) → O(1)
May modify input array
Remove duplicates, move zeros
Pointer Instead of Copy
Avoid array cloning
Need to track positions carefully
Reverse string, partition array
Overwrite Strategy
Reuse input array for output
Original data lost
Merge sorted arrays in-place
Cycle Detection Memory
O(n) → O(1)
Only works for cyclic structures
Floyd's algorithm vs HashSet
Example: Reverse string in-place
function reverseString(s) { let left = 0; let right = s.length - 1; while (left < right) { // Swap characters [s[left], s[right]] = [s[right], s[left]]; left++; right--; } // O(1) space - no extra array needed}// ['h','e','l','l','o'] -> ['o','l','l','e','h']
Note: Two pointers technique achieves O(1) space complexity for many problems that would otherwise require O(n) space. The key is recognizing when pointers can replace additional data structures like HashSets or extra arrays.
Two Pointers Pattern Summary
Opposite Ends: Start from both ends, move based on condition (sorted arrays)
Fast-Slow: Different speeds reveal patterns (cycle detection, middle element)
Same Direction: One tracks position, other scans (remove duplicates)
Partitioning: Maintain invariants between pointer regions (Dutch flag)
Key Benefit: O(n) time with O(1) space - optimal for in-place operations
Warning: Always validate pointer positions before dereferencing. In fast-slow patterns, check both fast and fast.next to prevent null pointer errors. For opposite-ends technique, ensure left < right condition is correct.