Chapter 15

Home

Two Pointer Technique

Instead of nested loops (O(N²)), use two indices that move through the array in a single pass (O(N)). This is a cornerstone of efficient algorithms.

The Idea

Two pointers start at different positions and move toward each other or in the same direction. Each pointer advances independently, and you process only what's between them.

left right

Problem: Pair Sum to Target

Given a sorted array and a target, find two numbers that add up to the target. One pointer at each end; if the sum is too small, move the left pointer right; if too large, move the right pointer left.

Sample input:
5 10
1 3 4 6 9

Expected output:
1 9  (or 4 6)

C++

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n, target; cin >> n >> target;
    vector<int> arr(n);
    for (int i = 0; i < n; i++) cin >> arr[i];

    int left = 0, right = n - 1;
    while (left < right) {
        int sum = arr[left] + arr[right];
        if (sum == target) {
            cout << arr[left] << " " << arr[right] << "\n";
            return 0;
        }
        if (sum < target) left++;
        else right--;
    }
    cout << "not found\n";
    return 0;
}

Rust

use std::io::{self, Read};

fn main() {
    let mut input = String::new();
    io::stdin().lock().read_to_string(&mut input).unwrap();
    let nums: Vec<i32> = input
        .split_whitespace()
        .map(|x| x.parse().unwrap())
        .collect();

    let n = nums[0] as usize;
    let target = nums[1];
    let arr = &nums[2..2 + n];
    let mut left = 0;
    let mut right = n - 1;

    while left < right {
        match (arr[left] + arr[right]).cmp(&target) {
            std::cmp::Ordering::Equal => {
                println!("{} {}", arr[left], arr[right]);
                return;
            }
            std::cmp::Ordering::Less => left += 1,
            std::cmp::Ordering::Greater => right -= 1,
        }
    }
    println!("not found");
}

Two Pointers Moving Together

Sometimes both pointers start at the same end, one moving faster. This is common in linked list problems (slow/fast) or when removing duplicates from a sorted array.

C++ — remove duplicates in-place

int remove_duplicates(vector<int>& arr) {
    if (arr.empty()) return 0;
    int j = 0;
    for (int i = 1; i < arr.size(); i++) {
        if (arr[i] != arr[j]) {
            j++;
            arr[j] = arr[i];
        }
    }
    return j + 1;  // new length
}

Rust — remove duplicates in-place

fn remove_duplicates(arr: &mut [i32]) -> usize {
    if arr.is_empty() { return 0; }
    let mut j = 0;
    for i in 1..arr.len() {
        if arr[i] != arr[j] {
            j += 1;
            arr[j] = arr[i];
        }
    }
    j + 1
}

Key Takeaways

Practice