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.

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
xand use binary search to look fortarget - xin 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.
- Initialize Pointers: Create a
leftpointer at the start of the array (index 0) and arightpointer at the end (indexn-1). - 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 theleftpointer to the right (left += 1). - If
current_sum > target: You need a smaller sum. The only way to decrease the sum is to move therightpointer to the left (right -= 1).
- Calculate
This process systematically eliminates pairs from consideration, ensuring you check all valid possibilities in a single pass.

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
- Initial:
left = 0(value -5),right = 4(value 11).current_sum = -5 + 11 = 6. - Step 1:
current_sum < target(6 < 12), soleftbecomes 1.left = 1(value 1),right = 4(value 11).current_sum = 1 + 11 = 12.
- 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:
- Initialize
left = 0,right = n-1. - Create a result array of the same size, filled with placeholders.
- Use a third pointer,
write_pos, starting from the end of the result array (n-1). - In a loop, compare
abs(arr[left])andabs(arr[right]).- If
abs(arr[left])is smaller, the square ofarr[right]is larger. Place it atresult[write_pos]and decrementright. - Otherwise, the square of
arr[left]is larger or equal. Place it atresult[write_pos]and incrementleft.
- If
- Decrement
write_posin 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.