Skip to content

Two Pointer Pattern ​

Efficiently traverse arrays from both ends or with synchronized pointers


Pattern Overview ​

The Two Pointer Technique is one of the most powerful and versatile algorithmic patterns used in coding interviews. It involves using two indices (pointers) that traverse a data structure—such as an array, list, or string—either toward each other or in the same direction to solve problems more efficiently.

Why Use Two Pointers? ​

  • Time Complexity Reduction: Converts O(n^2) brute force solutions to O(n)
  • Space Efficiency: Typically requires O(1) extra space
  • In-Place Operations: Enables modifications without extra data structures
  • Simplicity: Once mastered, provides clean and elegant solutions

When to Use Two Pointers ​

Strong Signals:

  • Input is sorted or has some ordering property
  • Need to find pairs or triplets satisfying a condition
  • Problem involves comparing elements at different positions
  • Need to partition an array in-place
  • Working with palindromes or symmetric structures
  • Need to remove duplicates or specific elements
  • Merging or comparing two sorted arrays

Types of Two Pointer ​

1. Opposite Direction (Converging) ​

Both pointers start at opposite ends and move toward each other until they meet.

Initial:    [1, 2, 3, 4, 5, 6, 7]
             ^                 ^
            left             right

Step 1:     [1, 2, 3, 4, 5, 6, 7]
                ^           ^
               left       right

Step 2:     [1, 2, 3, 4, 5, 6, 7]
                   ^     ^
                  left  right

Final:      [1, 2, 3, 4, 5, 6, 7]
                      ^
                 left = right (converged)

Use Cases:

  • Two Sum in sorted array
  • Container with Most Water
  • Valid Palindrome
  • Trapping Rain Water
  • Three Sum (outer loop + two pointers)

2. Same Direction (Fast/Slow) ​

Both pointers start at the same position but move at different speeds or under different conditions.

Remove Duplicates Example:
Initial:    [1, 1, 2, 2, 3]
             ^
          slow,fast

Step 1:     [1, 1, 2, 2, 3]    (arr[fast] == arr[slow], skip)
             ^  ^
           slow fast

Step 2:     [1, 2, 2, 2, 3]    (arr[fast] != arr[slow], copy)
                ^  ^
              slow fast

Step 3:     [1, 2, 2, 2, 3]    (arr[fast] == arr[slow], skip)
                ^     ^
              slow   fast

Step 4:     [1, 2, 3, 2, 3]    (arr[fast] != arr[slow], copy)
                   ^     ^
                 slow   fast

Result:     [1, 2, 3] (first 3 elements)

Use Cases:

  • Remove Duplicates from Sorted Array
  • Move Zeroes
  • Remove Element
  • Cycle Detection (Floyd's Algorithm)
  • Finding middle of linked list

3. Two Arrays ​

One pointer in each of two different arrays, useful for merging or comparing.

Merge Two Sorted Arrays:
Array A:    [1, 3, 5]
             ^
             i

Array B:    [2, 4, 6]
             ^
             j

Compare A[i] and B[j], take smaller, advance that pointer.

Result:     [1, 2, 3, 4, 5, 6]

Use Cases:

  • Merge Sorted Arrays
  • Intersection of Two Arrays
  • Compare Version Numbers

Mermaid Diagram ​

Opposite Direction (Converging) Visualization ​

Same Direction (Fast/Slow) Visualization ​

Algorithm Decision Flowchart ​


Template Code ​

Opposite Direction Template ​

python
def two_pointer_opposite(arr: list, target: int) -> list:
    """
    Template for problems where pointers converge from both ends.
    Examples: Two Sum II, Valid Palindrome, Container With Most Water

    Time: O(n), Space: O(1)
    """
    left, right = 0, len(arr) - 1

    while left < right:
        current_sum = arr[left] + arr[right]

        if current_sum == target:
            return [left, right]  # Found the answer
        elif current_sum < target:
            left += 1   # Need larger sum, move left pointer right
        else:
            right -= 1  # Need smaller sum, move right pointer left

    return []  # No solution found
java
int[] twoPointerOpposite(int[] arr, int target) {
    // Template: converging pointers. Time: O(n), Space: O(1)
    int left = 0, right = arr.length - 1;
    while (left < right) {
        int sum = arr[left] + arr[right];
        if (sum == target) return new int[]{left, right};
        else if (sum < target) left++;
        else right--;
    }
    return new int[]{};
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Each pointer moves at most n times total, and they never backtrack
  • Space: O(1) - Only two integer pointers are used regardless of input size

Same Direction Template ​

python
def two_pointer_same_direction(arr: list) -> int:
    """
    Template for problems where both pointers move in same direction.
    Examples: Remove Duplicates, Move Zeroes, Remove Element

    Time: O(n), Space: O(1)
    """
    if not arr:
        return 0

    slow = 0  # Points to position for next unique element

    for fast in range(len(arr)):
        if condition(arr[fast], arr[slow]):  # Define your condition
            slow += 1
            arr[slow] = arr[fast]  # Write unique element

    return slow + 1  # Length of processed array
java
int twoPointerSameDirection(int[] arr) {
    // Template: slow writes, fast scans. Time: O(n), Space: O(1)
    if (arr.length == 0) return 0;
    int slow = 0;
    for (int fast = 0; fast < arr.length; fast++) {
        if (/* condition */ arr[fast] != arr[slow]) {
            slow++;
            arr[slow] = arr[fast];
        }
    }
    return slow + 1;
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Fast pointer iterates through array once, slow pointer advances conditionally
  • Space: O(1) - In-place modification using only two integer pointers

Fast/Slow Pointer (Cycle Detection) Template ​

python
def floyd_cycle_detection(head: 'ListNode') -> bool:
    """
    Template for cycle detection in linked lists.
    Also known as Floyd's Tortoise and Hare algorithm.

    Time: O(n), Space: O(1)
    """
    if not head or not head.next:
        return False

    slow = head       # Tortoise: moves 1 step
    fast = head.next  # Hare: moves 2 steps

    while fast and fast.next:
        if slow == fast:
            return True  # Cycle detected
        slow = slow.next
        fast = fast.next.next

    return False  # No cycle
java
boolean floydCycleDetection(ListNode head) {
    // Template: fast/slow cycle detection. Time: O(n), Space: O(1)
    if (head == null || head.next == null) return false;
    ListNode slow = head, fast = head.next;
    while (fast != null && fast.next != null) {
        if (slow == fast) return true;
        slow = slow.next;
        fast = fast.next.next;
    }
    return false;
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - If cycle exists, fast catches slow within cycle length iterations; if not, fast reaches end in n/2 steps
  • Space: O(1) - Only two pointers used regardless of list length

Two Arrays Template ​

python
def merge_two_sorted(arr1: list, arr2: list) -> list:
    """
    Template for problems involving two sorted arrays.
    Examples: Merge Sorted Array, Intersection of Two Arrays

    Time: O(n + m), Space: O(n + m) for result
    """
    result = []
    i, j = 0, 0

    while i < len(arr1) and j < len(arr2):
        if arr1[i] <= arr2[j]:
            result.append(arr1[i])
            i += 1
        else:
            result.append(arr2[j])
            j += 1

    # Append remaining elements
    result.extend(arr1[i:])
    result.extend(arr2[j:])

    return result
java
int[] mergeTwoSorted(int[] arr1, int[] arr2) {
    // Template: two sorted arrays. Time: O(n+m), Space: O(n+m)
    int[] result = new int[arr1.length + arr2.length];
    int i = 0, j = 0, k = 0;
    while (i < arr1.length && j < arr2.length) {
        if (arr1[i] <= arr2[j]) result[k++] = arr1[i++];
        else result[k++] = arr2[j++];
    }
    while (i < arr1.length) result[k++] = arr1[i++];
    while (j < arr2.length) result[k++] = arr2[j++];
    return result;
}

Complexity: Time O(n + m) · Space O(n + m)

  • Time: O(n + m) - Each element from both arrays is processed exactly once
  • Space: O(n + m) - Result array stores all elements from both input arrays

Classic Problems ​

Two Sum II - Input Array Is Sorted ​

Problem: Given a 1-indexed sorted array and a target, find two numbers that add up to the target.

LeetCode: 167. Two Sum II - Input Array Is Sorted

python
def twoSum(numbers: list[int], target: int) -> list[int]:
    """
    Two pointers approach for sorted array two sum.

    Key Insight: Since array is sorted, if sum < target, we need larger
    numbers (move left pointer right). If sum > target, we need smaller
    numbers (move right pointer left).

    Time: O(n) - single pass through array
    Space: O(1) - only two pointers used
    """
    left, right = 0, len(numbers) - 1

    while left < right:
        current_sum = numbers[left] + numbers[right]

        if current_sum == target:
            return [left + 1, right + 1]  # 1-indexed
        elif current_sum < target:
            left += 1
        else:
            right -= 1

    return []  # Should never reach here per problem constraints

# Example:
# Input: numbers = [2, 7, 11, 15], target = 9
# Output: [1, 2] (indices of 2 and 7)
java
int[] twoSum(int[] numbers, int target) {
    // LeetCode 167. Time: O(n), Space: O(1)
    int left = 0, right = numbers.length - 1;
    while (left < right) {
        int sum = numbers[left] + numbers[right];
        if (sum == target) return new int[]{left + 1, right + 1}; // 1-indexed
        else if (sum < target) left++;
        else right--;
    }
    return new int[]{};
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Each element visited at most once as pointers converge from both ends
  • Space: O(1) - Only two integer pointers used, no additional data structures

Remove Duplicates from Sorted Array ​

Problem: Remove duplicates in-place from a sorted array and return the new length.

LeetCode: 26. Remove Duplicates from Sorted Array

python
def removeDuplicates(nums: list[int]) -> int:
    """
    Fast/slow pointer approach for removing duplicates.

    Key Insight: Slow pointer marks the position for the next unique element.
    Fast pointer scans through the array looking for new unique values.

    Time: O(n) - single pass through array
    Space: O(1) - in-place modification
    """
    if not nums:
        return 0

    slow = 0  # Position of last unique element

    for fast in range(1, len(nums)):
        if nums[fast] != nums[slow]:
            slow += 1
            nums[slow] = nums[fast]

    return slow + 1  # Length of unique portion

# Example:
# Input: nums = [1, 1, 2, 2, 3, 3, 4]
# Output: 4 (array becomes [1, 2, 3, 4, ...])
java
int removeDuplicates(int[] nums) {
    // LeetCode 26. Time: O(n), Space: O(1)
    if (nums.length == 0) return 0;
    int slow = 0;
    for (int fast = 1; fast < nums.length; fast++) {
        if (nums[fast] != nums[slow]) {
            slow++;
            nums[slow] = nums[fast];
        }
    }
    return slow + 1;
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Single pass through array with fast pointer; slow pointer only advances when unique element found
  • Space: O(1) - In-place modification, no extra space used

Container With Most Water ​

Problem: Given heights representing vertical lines, find two lines that form a container holding the most water.

LeetCode: 11. Container With Most Water

python
def maxArea(height: list[int]) -> int:
    """
    Two pointers approach to maximize water container.

    Key Insight: Water contained = min(height[left], height[right]) * (right - left)
    Always move the pointer pointing to the shorter line, because:
    - Moving the taller line can only decrease or maintain the width
    - The height is limited by the shorter line anyway
    - Moving the shorter line might find a taller line to increase area

    Time: O(n) - single pass through array
    Space: O(1) - only two pointers
    """
    left, right = 0, len(height) - 1
    max_water = 0

    while left < right:
        # Calculate current area
        width = right - left
        current_height = min(height[left], height[right])
        current_area = width * current_height
        max_water = max(max_water, current_area)

        # Move the pointer at shorter height
        if height[left] < height[right]:
            left += 1
        else:
            right -= 1

    return max_water

# Example:
# Input: height = [1, 8, 6, 2, 5, 4, 8, 3, 7]
# Output: 49 (between index 1 and 8, heights 8 and 7)
java
int maxArea(int[] height) {
    // LeetCode 11. Time: O(n), Space: O(1)
    int left = 0, right = height.length - 1, maxWater = 0;
    while (left < right) {
        int area = Math.min(height[left], height[right]) * (right - left);
        maxWater = Math.max(maxWater, area);
        if (height[left] < height[right]) left++;
        else right--;
    }
    return maxWater;
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Each pointer moves at most n times total as they converge toward center
  • Space: O(1) - Only two pointers and a max tracker variable used

Visual Explanation:

    8           8
    |           |   7
    |   6       |   |
    |   |   5   |   |
    |   |   | 4 |   |
    |   |   | | | 3 |
    |   | 2 | | | | |
  1 |   | | | | | | |
  | |   | | | | | | |
  0 1 2 3 4 5 6 7 8

  Max area = min(8, 7) * (8 - 1) = 7 * 7 = 49

Complexity Analysis:

  • Time: O(n) - each pointer moves at most n times total
  • Space: O(1) - constant extra space

Trapping Rain Water ​

Problem: Given elevation map heights, compute how much water can be trapped after raining.

LeetCode: 42. Trapping Rain Water

python
def trap(height: list[int]) -> int:
    """
    Two pointers approach to calculate trapped rain water.

    Key Insight: Water at any position = min(left_max, right_max) - height[i]
    We use two pointers and track max heights from both directions.
    Process the side with smaller max height (that's the bottleneck).

    Time: O(n) - single pass through array
    Space: O(1) - only pointers and max trackers
    """
    if not height:
        return 0

    left, right = 0, len(height) - 1
    left_max, right_max = height[left], height[right]
    water = 0

    while left < right:
        if left_max < right_max:
            # Left side is the bottleneck
            left += 1
            left_max = max(left_max, height[left])
            water += left_max - height[left]
        else:
            # Right side is the bottleneck
            right -= 1
            right_max = max(right_max, height[right])
            water += right_max - height[right]

    return water

# Example:
# Input: height = [0, 1, 0, 2, 1, 0, 1, 3, 2, 1, 2, 1]
# Output: 6
java
int trap(int[] height) {
    // LeetCode 42. Two-pointer O(1) space. Time: O(n), Space: O(1)
    int left = 0, right = height.length - 1;
    int leftMax = height[0], rightMax = height[height.length - 1];
    int water = 0;
    while (left < right) {
        if (leftMax < rightMax) {
            left++;
            leftMax = Math.max(leftMax, height[left]);
            water += leftMax - height[left];
        } else {
            right--;
            rightMax = Math.max(rightMax, height[right]);
            water += rightMax - height[right];
        }
    }
    return water;
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Single pass with two pointers converging from both ends
  • Space: O(1) - Only two pointers and two max trackers, no auxiliary arrays needed

Visual Explanation:

              3
          2   |   2
      2   | 1 | | | 1
  1   | 1 | | | | | |
  | 0 | 0 | | 0 | | | |
  0 1 2 3 4 5 6 7 8 9 10 11

  Water fills the gaps:
  - Index 2: min(1, 3) - 0 = 1
  - Index 4: min(2, 3) - 1 = 1
  - Index 5: min(2, 3) - 0 = 2
  - Index 6: min(2, 3) - 1 = 1
  - Index 9: min(3, 2) - 1 = 1
  Total: 6 units

Complexity Analysis:

  • Time: O(n) - single pass
  • Space: O(1) - constant space

3Sum ​

Problem: Find all unique triplets in the array that sum to zero.

LeetCode: 15. 3Sum

python
def threeSum(nums: list[int]) -> list[list[int]]:
    """
    Sort + Two Pointers approach for 3Sum.

    Key Insight: Fix one number, then use two pointers to find pairs
    that sum to the negative of the fixed number.

    Time: O(n^2) - outer loop O(n) * inner two pointers O(n)
    Space: O(1) or O(n) depending on sorting implementation
    """
    nums.sort()
    result = []
    n = len(nums)

    for i in range(n - 2):
        # Skip duplicates for first element
        if i > 0 and nums[i] == nums[i - 1]:
            continue

        # Early termination: if smallest is positive, no solution
        if nums[i] > 0:
            break

        target = -nums[i]
        left, right = i + 1, n - 1

        while left < right:
            current_sum = nums[left] + nums[right]

            if current_sum == target:
                result.append([nums[i], nums[left], nums[right]])

                # Skip duplicates for second element
                while left < right and nums[left] == nums[left + 1]:
                    left += 1
                # Skip duplicates for third element
                while left < right and nums[right] == nums[right - 1]:
                    right -= 1

                left += 1
                right -= 1
            elif current_sum < target:
                left += 1
            else:
                right -= 1

    return result

# Example:
# Input: nums = [-1, 0, 1, 2, -1, -4]
# Output: [[-1, -1, 2], [-1, 0, 1]]
java
List<List<Integer>> threeSum(int[] nums) {
    // LeetCode 15. Time: O(n²), Space: O(1) extra
    Arrays.sort(nums);
    List<List<Integer>> result = new ArrayList<>();
    int n = nums.length;
    for (int i = 0; i < n - 2; i++) {
        if (i > 0 && nums[i] == nums[i - 1]) continue;
        if (nums[i] > 0) break;
        int left = i + 1, right = n - 1;
        while (left < right) {
            int sum = nums[i] + nums[left] + nums[right];
            if (sum == 0) {
                result.add(Arrays.asList(nums[i], nums[left], nums[right]));
                while (left < right && nums[left] == nums[left + 1]) left++;
                while (left < right && nums[right] == nums[right - 1]) right--;
                left++; right--;
            } else if (sum < 0) left++;
            else right--;
        }
    }
    return result;
}

Complexity: Time O(n^2) · Space O(1) to O(n)

  • Time: O(n^2) - Outer loop iterates n times, inner two-pointer scan is O(n) each iteration
  • Space: O(1) to O(n) - Depends on sorting algorithm; in-place sort uses O(1), otherwise O(n)

Valid Palindrome ​

Problem: Determine if a string is a palindrome, considering only alphanumeric characters.

LeetCode: 125. Valid Palindrome

python
def isPalindrome(s: str) -> bool:
    """
    Two pointers approach for palindrome check.

    Key Insight: Compare characters from both ends, skipping non-alphanumeric.

    Time: O(n) - single pass through string
    Space: O(1) - only two pointers
    """
    left, right = 0, len(s) - 1

    while left < right:
        # Skip non-alphanumeric from left
        while left < right and not s[left].isalnum():
            left += 1
        # Skip non-alphanumeric from right
        while left < right and not s[right].isalnum():
            right -= 1

        # Compare characters (case-insensitive)
        if s[left].lower() != s[right].lower():
            return False

        left += 1
        right -= 1

    return True

# Example:
# Input: s = "A man, a plan, a canal: Panama"
# Output: True
java
boolean isPalindrome(String s) {
    // LeetCode 125. Time: O(n), Space: O(1)
    int left = 0, right = s.length() - 1;
    while (left < right) {
        while (left < right && !Character.isLetterOrDigit(s.charAt(left))) left++;
        while (left < right && !Character.isLetterOrDigit(s.charAt(right))) right--;
        if (Character.toLowerCase(s.charAt(left)) != Character.toLowerCase(s.charAt(right)))
            return false;
        left++; right--;
    }
    return true;
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Each character visited at most once by either pointer
  • Space: O(1) - Only two integer pointers used, no string copies created

Move Zeroes ​

Problem: Move all zeroes to the end while maintaining relative order of non-zero elements.

LeetCode: 283. Move Zeroes

python
def moveZeroes(nums: list[int]) -> None:
    """
    Fast/slow pointer approach for moving zeroes.

    Key Insight: Slow pointer tracks position for next non-zero.
    Fast pointer finds non-zero elements.

    Time: O(n) - single pass
    Space: O(1) - in-place
    """
    slow = 0  # Position for next non-zero element

    # Move all non-zero elements to the front
    for fast in range(len(nums)):
        if nums[fast] != 0:
            nums[slow], nums[fast] = nums[fast], nums[slow]
            slow += 1

    # All elements after slow are already zero due to swaps

# Example:
# Input: nums = [0, 1, 0, 3, 12]
# Output: nums = [1, 3, 12, 0, 0] (in-place)
java
void moveZeroes(int[] nums) {
    // LeetCode 283. Time: O(n), Space: O(1)
    int slow = 0;
    for (int fast = 0; fast < nums.length; fast++) {
        if (nums[fast] != 0) {
            int tmp = nums[slow]; nums[slow] = nums[fast]; nums[fast] = tmp;
            slow++;
        }
    }
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Single pass with fast pointer; swaps are O(1) operations
  • Space: O(1) - In-place modification using only two pointers

Linked List Cycle ​

Problem: Detect if a linked list has a cycle.

LeetCode: 141. Linked List Cycle

python
def hasCycle(head: 'ListNode') -> bool:
    """
    Floyd's Cycle Detection (Tortoise and Hare).

    Key Insight: If there's a cycle, fast pointer will eventually
    catch up to slow pointer. If no cycle, fast reaches end.

    Why it works: In a cycle, fast gains 1 step per iteration on slow.
    Eventually they must meet.

    Time: O(n) - at most 2n steps before detection
    Space: O(1) - only two pointers
    """
    if not head or not head.next:
        return False

    slow = head
    fast = head

    while fast and fast.next:
        slow = slow.next        # Move 1 step
        fast = fast.next.next   # Move 2 steps

        if slow == fast:
            return True  # Cycle detected

    return False  # Fast reached end, no cycle
java
boolean hasCycle(ListNode head) {
    // LeetCode 141. Time: O(n), Space: O(1)
    ListNode slow = head, fast = head;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
        if (slow == fast) return true;
    }
    return false;
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Fast pointer travels at most 2n nodes before either reaching end or catching slow in cycle
  • Space: O(1) - Only two pointers used, independent of list size

Sort Colors (Dutch National Flag) ​

Problem: Sort an array containing only 0, 1, and 2 in-place.

LeetCode: 75. Sort Colors

python
def sortColors(nums: list[int]) -> None:
    """
    Three pointers approach (Dutch National Flag algorithm).

    Key Insight: Partition array into three sections:
    [0...low-1] = 0s, [low...high] = 1s, [high+1...n-1] = 2s

    Time: O(n) - single pass
    Space: O(1) - in-place
    """
    low, mid, high = 0, 0, len(nums) - 1

    while mid <= high:
        if nums[mid] == 0:
            nums[low], nums[mid] = nums[mid], nums[low]
            low += 1
            mid += 1
        elif nums[mid] == 1:
            mid += 1
        else:  # nums[mid] == 2
            nums[mid], nums[high] = nums[high], nums[mid]
            high -= 1
            # Don't increment mid, need to check swapped value

# Example:
# Input: nums = [2, 0, 2, 1, 1, 0]
# Output: nums = [0, 0, 1, 1, 2, 2] (in-place)
java
void sortColors(int[] nums) {
    // LeetCode 75. Dutch National Flag. Time: O(n), Space: O(1)
    int low = 0, mid = 0, high = nums.length - 1;
    while (mid <= high) {
        if (nums[mid] == 0) {
            int tmp = nums[low]; nums[low] = nums[mid]; nums[mid] = tmp;
            low++; mid++;
        } else if (nums[mid] == 1) {
            mid++;
        } else {
            int tmp = nums[mid]; nums[mid] = nums[high]; nums[high] = tmp;
            high--; // don't increment mid
        }
    }
}

Complexity: Time O(n) · Space O(1)

  • Time: O(n) - Each element is examined at most twice (once by mid, possibly once after swap from high)
  • Space: O(1) - In-place partitioning using only three pointers

Pattern Recognition ​

Key Indicators for Two Pointer Pattern ​

SignalPattern TypeExample Problem
Sorted array + find pairOpposite DirectionTwo Sum II
Palindrome checkOpposite DirectionValid Palindrome
Find maximum/minimum with constraintsOpposite DirectionContainer With Most Water
Remove/deduplicate in-placeSame DirectionRemove Duplicates
Partition arraySame DirectionMove Zeroes, Sort Colors
Cycle detectionFast/SlowLinked List Cycle
Two sorted arraysTwo ArraysMerge Sorted Array
Sum equals target (sorted)Opposite Direction3Sum, 4Sum

Questions to Ask Yourself ​

  1. Is the input sorted? -> Strong signal for two pointers
  2. Am I looking for pairs/triplets? -> Consider opposite direction
  3. Do I need to modify in-place? -> Consider same direction
  4. Is this about a cycle? -> Use fast/slow
  5. Are there two arrays to merge/compare? -> Use two array pointers

Complexity Comparison ​

ApproachTimeSpaceWhen to Use
Brute Force (nested loops)O(n^2)O(1)Never for two pointer problems
Hash MapO(n)O(n)When order doesn't matter
Two PointersO(n)O(1)When input has structure (sorted)
Sort + Two PointersO(n log n)O(1)When can afford sorting

Interview Applications ​

Two pointer problems are frequently asked in interviews and other top tech companies. Here are common problem types and practice recommendations:

Frequently Asked ​

  1. Container With Most Water - Classic opposite direction problem
  2. Trapping Rain Water - Advanced two pointer with running max
  3. 3Sum / 4Sum - Sort + nested two pointer
  4. Two Sum II - Foundation problem for the pattern
  5. Merge Sorted Array - Two array pointer problem
  6. Valid Palindrome II - Allow one deletion variant
  7. Remove Duplicates from Sorted Array - In-place modification

Interview Tips ​

Before Coding:

  • Clarify if the input is sorted
  • Ask about duplicates and how to handle them
  • Confirm space complexity requirements
  • Discuss whether in-place modification is acceptable

During Implementation:

  • Start with pointer initialization
  • Clearly define loop termination condition
  • Handle edge cases (empty array, single element)
  • Be careful with off-by-one errors

Common Mistakes to Avoid:

  • Using <= instead of < in while condition
  • Not handling duplicates properly in 3Sum/4Sum
  • Forgetting to move pointers inside the loop
  • Not updating max/min values correctly

Practice Resources ​


Quick Reference Card ​

+------------------------------------------------------------------+
|                    TWO POINTER QUICK REFERENCE                    |
+------------------------------------------------------------------+

PATTERN TYPES:
--------------
1. Opposite Direction: left=0, right=n-1, converge to center
2. Same Direction:     slow=0, fast moves ahead, both go forward
3. Two Arrays:         i in arr1, j in arr2, process together

TEMPLATE - OPPOSITE DIRECTION:
------------------------------
left, right = 0, len(arr) - 1
while left < right:
    if condition_met:
        return result
    elif need_larger:
        left += 1
    else:
        right -= 1

TEMPLATE - SAME DIRECTION:
--------------------------
slow = 0
for fast in range(len(arr)):
    if should_keep(arr[fast]):
        arr[slow] = arr[fast]
        slow += 1
return slow

TEMPLATE - CYCLE DETECTION:
---------------------------
slow = fast = head
while fast and fast.next:
    slow = slow.next
    fast = fast.next.next
    if slow == fast:
        return True  # cycle found
return False

WHEN TO USE:
------------
[x] Sorted array                    -> Two pointers likely optimal
[x] Find pairs summing to target    -> Opposite direction
[x] Remove duplicates in-place      -> Same direction (fast/slow)
[x] Check palindrome                -> Opposite direction
[x] Cycle in linked list            -> Fast/slow pointers
[x] Merge two sorted arrays         -> Two array pointers
[x] Partition array (0s, 1s, 2s)   -> Three pointers (Dutch flag)

COMPLEXITY:
-----------
Time:  O(n) for single pass, O(n^2) for nested (like 3Sum)
Space: O(1) typically (main advantage over hash-based solutions)

COMMON PROBLEMS:
----------------
- Two Sum II              - Container With Most Water
- 3Sum / 4Sum            - Trapping Rain Water
- Remove Duplicates      - Valid Palindrome
- Move Zeroes            - Linked List Cycle
- Sort Colors            - Merge Sorted Array

EDGE CASES TO CHECK:
--------------------
[ ] Empty array
[ ] Single element
[ ] All same elements
[ ] Already sorted (ascending/descending)
[ ] Negative numbers
[ ] Duplicates

+------------------------------------------------------------------+

Additional Practice Problems ​

Easy ​

Medium ​

Hard ​


Sources ​