Submissions disabled: This deployment is running in read-only mode for safety. Code execution is not available here.
← Problem Solving Patterns

Two Pointers Technique

Two Pointers Technique

The two pointers technique is a pattern where you use two indices to traverse a data structure, often from different ends or at different speeds.

When to Use Two Pointers

  • Searching for pairs in a sorted array
  • Reversing or comparing elements
  • Finding subarrays with certain properties
  • Removing duplicates

Pattern 1: Opposite Direction

Start one pointer at the beginning, one at the end, and move them toward each other.

Example: Is Palindrome?

def is_palindrome(s):
    left = 0
    right = len(s) - 1

    while left < right:
        if s[left] != s[right]:
            return False
        left += 1
        right -= 1

    return True

print(is_palindrome("racecar"))  # True
print(is_palindrome("hello"))    # False

Example: Two Sum (Sorted Array)

Given a sorted array, find two numbers that add up to a target:

def two_sum_sorted(numbers, target):
    left = 0
    right = len(numbers) - 1

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

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

    return []  # No solution found

nums = [1, 2, 3, 4, 6]
print(two_sum_sorted(nums, 6))  # [1, 3] (indices of 2 and 4)

Pattern 2: Same Direction (Fast/Slow)

Both pointers move in the same direction, but at different speeds.

Example: Remove Duplicates (In-Place)

def remove_duplicates(nums):
    if not nums:
        return 0

    slow = 0

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

    return slow + 1  # Length of unique elements

nums = [1, 1, 2, 2, 3, 4, 4]
length = remove_duplicates(nums)
print(nums[:length])  # [1, 2, 3, 4]

Example: Move Zeros to End

def move_zeros(nums):
    slow = 0

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

    return nums

print(move_zeros([0, 1, 0, 3, 12]))  # [1, 3, 12, 0, 0]

Pattern 3: Sliding Window Variant

Sometimes two pointers define a "window" in the array:

def longest_substring_without_repeating(s):
    seen = set()
    left = 0
    max_length = 0

    for right in range(len(s)):
        while s[right] in seen:
            seen.remove(s[left])
            left += 1

        seen.add(s[right])
        max_length = max(max_length, right - left + 1)

    return max_length

print(longest_substring_without_repeating("abcabcbb"))  # 3 ("abc")

Key Insights

  1. Sorted arrays - Two pointers from opposite ends often work well
  2. In-place modifications - Fast/slow pointer pattern
  3. Time complexity - Usually O(n) since each pointer moves at most n times
  4. Space complexity - Usually O(1) since we only use pointer variables

Practice Problems

After this lesson, try these problems:
- Two Sum (if the array is sorted)
- Valid Palindrome
- Container With Most Water
- 3Sum

Tip: When you see "find a pair" or "in-place" in a problem, consider two pointers!