Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 19

Two-Pointer Technique for Sorted Arrays

Recommended resources

Hello! Welcome to the first lesson in our module on "Two-Pointers and Sliding Window."

In our last module, we wrapped up our study of sorting algorithms by looking at Counting Sort. We saw how specific properties of data—like being integers in a limited range—can allow for specialized, highly efficient algorithms. A key takeaway was that having sorted data is often a prerequisite for many fast algorithms. Today, we'll see that principle in action.

This lesson addresses the learning outcome: Apply the two-pointer technique to solve problems on sorted arrays. We'll focus on a powerful pattern that can significantly speed up your code, often transforming a slow quadratic solution into a blazing-fast linear one. This is a fundamental technique in competitive programming.

The Two-Pointer Technique: An Overview

At its core, the "two-pointer" technique is exactly what it sounds like: you use two integer indices (the "pointers") to traverse a data structure, usually an array. By moving these pointers according to some logic, you can efficiently process pairs or subarrays.

There are a few common patterns. For this lesson, we will focus on the most common one used with sorted arrays: pointers at opposite ends moving towards each other.

Two-Pointer Technique on a Sorted Array
This image illustrates the "opposite-ends" two-pointer pattern. One pointer starts at the beginning of the array, and the other starts at the end. They move towards the center, examining elements as they go.

This technique shines when a problem involves finding pairs of elements in a sorted array that satisfy a certain condition. Let's dive into the classic problem that demonstrates this perfectly.


The "Two Sum" Problem on a Sorted Array

Imagine you're given a sorted array of integers and a target number. Your task is to find out if there's a pair of numbers in the array that adds up exactly to that target.

Problem: Given arr = [2, 7, 11, 15] and target = 9, find the pair.
Solution: The pair is (2, 7).

How would you solve this?

  • Brute-Force Approach: The most straightforward way is to use nested loops. The outer loop picks an element, and the inner loop checks every other element to see if their sum matches the target. This works, but with two nested loops, its time complexity is , which is too slow for large inputs in competitive programming.

  • A Better, but Not Optimal, Approach: Since the array is sorted, you could iterate through each element x and use binary search to look for target - x in the rest of the array. This would be an solution, which is much better, but we can still do better!

  • The Two-Pointer Approach (): This is where the magic happens. By using two pointers, we can solve this in a single pass.

To see a great visual explanation and a live coding demonstration of this approach, please watch the following video.

Visual introduction Two Pointer Algorithm | Data Structure and Algorithm for Coding Interviews

This video from Josh's DevBox provides a fantastic walkthrough of the 'Two Sum' problem on a sorted array. It starts by discussing the less efficient methods before demonstrating the logic and implementation of the optimal two-pointer solution.

Watch from 00:40 to 07:04. Pay close attention to how the left and right pointers move based on whether the current sum is less than, greater than, or equal to the target.

The Logic Explained

As the video demonstrates, the logic is elegant and relies entirely on the array being sorted.

  1. Initialize Pointers: Create a left pointer at the start of the array (index 0) and a right pointer at the end (index n-1).
  2. Loop and Check Sum: Loop as long as left < right:
    • Calculate current_sum = arr[left] + arr[right].
    • If current_sum == target: You've found your pair! You can stop.
    • If current_sum < target: You need a larger sum. Since the array is sorted, the only way to increase the sum is to move the left pointer to the right (left += 1).
    • If current_sum > target: You need a smaller sum. The only way to decrease the sum is to move the right pointer to the left (right -= 1).

This process systematically eliminates pairs from consideration, ensuring you check all valid possibilities in a single pass.

Two Pointer Technique: Solve Array Problems Efficiently
This diagram visualizes the core logic. Based on the comparison of the current sum with the target, you know exactly which pointer to move to get closer to the solution.

Python Implementation

Here is a clean Python implementation based on the logic we just discussed.

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

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

        if current_sum == target:
            # Found the pair, return their indices or values
            print(f"Pair found: ({arr[left]}, {arr[right]})")
            return True
        elif current_sum < target:
            # The sum is too small, need a larger number.
            # Move the left pointer to the right.
            left += 1
        else: # current_sum > target
            # The sum is too large, need a smaller number.
            # Move the right pointer to the left.
            right -= 1

    # If the loop finishes, no pair was found
    print("No pair found.")
    return False

# Example
my_array = [-3, 1, 4, 6, 10, 45]
my_target = 16
two_sum_sorted(my_array, my_target) # Output: Pair found: (6, 10)
Test your understanding!

Given the sorted array arr = [-5, 1, 4, 8, 11] and target = 12, trace the values of left, right, and current_sum at each step of the while loop.

Show answer
  1. Initial: left = 0 (value -5), right = 4 (value 11). current_sum = -5 + 11 = 6.
  2. Step 1: current_sum < target (6 < 12), so left becomes 1.
    • left = 1 (value 1), right = 4 (value 11). current_sum = 1 + 11 = 12.
  3. Step 2: current_sum == target (12 == 12). Pair found! The loop terminates.

Another Example: Squares of a Sorted Array

Let's look at another problem where this pattern is useful, but in a slightly different way.

Problem: Given an array of integers nums sorted in non-decreasing order (e.g., [-4, -1, 0, 3, 10]), return an array of the squares of each number, also sorted in non-decreasing order.

A simple O(n \log n) solution is to square every number and then sort the resulting array. But can we do it in O(n) time? Yes, with two pointers!

The key insight is that the largest squared values will come from the numbers with the largest absolute values, which are at the extremes of the sorted input array.

The following video explains this clever approach.

2 Pointers Algorithm - DSA Course in Python Lecture 12

Greg Hogg's video on this problem clearly explains why the largest squared values are on the outside and how to use two pointers to build the sorted result array efficiently.

Watch from 00:49 to 07:06. Focus on how the algorithm compares the absolute values at the left and right pointers to decide which square is larger and where to place it in the new array.

The logic is as follows:

  1. Initialize left = 0, right = n-1.
  2. Create a result array of the same size, filled with placeholders.
  3. Use a third pointer, write_pos, starting from the end of the result array (n-1).
  4. In a loop, compare abs(arr[left]) and abs(arr[right]).
    • If abs(arr[left]) is smaller, the square of arr[right] is larger. Place it at result[write_pos] and decrement right.
    • Otherwise, the square of arr[left] is larger or equal. Place it at result[write_pos] and increment left.
  5. Decrement write_pos in each iteration. Continue until the result array is filled.

This method builds the sorted array of squares from largest to smallest, all in one pass.


Conclusion

You've just learned one of the most common and effective patterns in competitive programming. The opposite-ends two-pointer technique is your go-to strategy when you encounter problems that involve finding pairs or processing elements from both ends of a sorted array.

Key Takeaways:

  • The two-pointer technique is used to efficiently process arrays in linear time, .
  • For sorted arrays, the "opposite-ends" pattern is extremely powerful.
  • The core logic involves initializing pointers at the start and end and moving them inward based on a condition related to the problem (e.g., sum vs. target).
  • This approach works by intelligently eliminating portions of the search space at each step, thanks to the sorted nature of the data.

Up Next:
The pattern we learned today is just one variant of the two-pointer technique. In the next lesson, we will explore another common pattern: the fast and slow pointers. You'll learn how it differs from the opposite-ends approach and what kinds of problems it is best suited to solve.