Basics of Two Pointer
The two-pointer technique uses two indices that move towards each other or in the same direction to process data efficiently.
It is commonly used when:
- Data is sorted or the problem has sequential properties.
- We need to find pairs/triplets or process subarrays without restarting from scratch.
- It works in O(n) for many problems that would otherwise require O(n²).
Common patterns:
- Opposite Direction: Pointers at start and end, moving toward each other (e.g., 2-Sum, Container with Most Water).
- Same Direction: Both pointers move forward, where one lags behind the other to form a range (e.g., Remove Duplicates from Sorted Array).
Two Pointer Algorithm – O(n) Time, O(1) Space
Example: 2 - Sum in Sorted Array
You are given an integer array arr[] sorted in non-decreasing order, and an integer target. Find two elements in the array whose sum equals target.
- If such a pair exists, return their indices in increasing order.
- If no such pair exists, return [-1, -1].
Approach - Using Two Pointers - O(n) Time and O(1) Space
We can maintain two pointers, left = 0 and right = n - 1, and calculate their sum S = arr[left] + arr[right].
- If S = target, then return left and right.
- If S < target, then we need to increase sum S, so we will increment left = left + 1.
- If S > target, then we need to decrease sum S, so we will decrement right = right - 1.
If at any point left >= right, then no pair with sum = target is found.
Algorithm:
Initialize left = 0 and right = n-1.
While left < right:
- If arr[left] + arr[right] == target, return the pair.
- If sum is smaller, move left++.
- If sum is larger, move right--.
Repeat until pointers meet.
vector<int> twoSumSorted(vector<int>& arr, int target) {
int left = 0, right = arr.size() - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target)
return {arr[left], arr[right]};
else if (sum < target)
left++;
else
right--;
}
return {};
}
import java.util.ArrayList;
class GfG {
public ArrayList<Integer> twoSumSorted(int[] arr, int target) {
int left = 0;
int right = arr.length - 1;
while (left < right) {
int sum = arr[left] + arr[right];
if (sum == target) {
ArrayList<Integer> result = new ArrayList<>();
result.add(arr[left]);
result.add(arr[right]);
return result;
} else if (sum < target) {
left++;
} else {
right--;
}
}
return new ArrayList<>();
}
}
def twoSumSorted(self, arr, target):
left = 0
right = len(arr) - 1
while left < right:
sum_val = arr[left] + arr[right]
if sum_val == target:
result = [arr[left], arr[right]]
return result
elif sum_val < target:
left += 1
else:
right -= 1
return []
using System;
using System.Collections.Generic;
class GfG{
public List<int> twoSumSorted(int[] arr, int target){
int left = 0;
int right = arr.Length - 1;
while (left < right){
int sum = arr[left] + arr[right];
if (sum == target){
List<int> result = new List<int>();
result.Add(arr[left]);
result.Add(arr[right]);
return result;
}
else if (sum < target){
left++;
}
else{
right--;
}
}
return new List<int>();
}
}
twoSumSorted(arr, target) {
let left = 0;
let right = arr.length - 1;
while (left < right) {
let sum = arr[left] + arr[right];
if (sum === target) {
return [arr[left], arr[right]];
} else if (sum < target) {
left++;
} else {
right--;
}
}
return [];
}
Example: Merge Two Sorted Arrays (No Extra Space)
Given two sorted arrays a[] and b[] of size n and m respectively, merge both the arrays and rearrange the elements such that the smallest n elements are in a[] and the remaining m elements are in b[]. All elements in a[] and b[] should be in sorted order.
Approach - Using Swap and Sort
We swap the rightmost element of a[] with the leftmost element of b[], then the second rightmost element of a[] with the second leftmost element of b[], and so on. This process continues until the selected element from a[] becomes larger than the selected element from b[]. At this point, the condition fails automatically and the process stops. Finally, sort both arrays to maintain the order.
Algorithm:
- Start from the end of both arrays.
- Compare and shift larger elements to the end of merged space.
- Fill remaining from other array if needed.
void mergeArrays(vector<int>& arr1, vector<int>& arr2) {
int n = arr1.size(), m = arr2.size();
int i = n - 1, j = 0;
// Swap elements if needed
while (i >= 0 && j < m) {
if (arr1[i] > arr2[j])
swap(arr1[i], arr2[j]);
i--;
j++;
}
// Sort both arrays
sort(arr1.begin(), arr1.end());
sort(arr2.begin(), arr2.end());
}
import java.util.Arrays;
public class Solution {
public void mergeArrays(int[] arr1, int[] arr2) {
int n = arr1.length, m = arr2.length;
int i = n - 1, j = 0;
// Swap elements if needed
while (i >= 0 && j < m) {
if (arr1[i] > arr2[j]) {
int temp = arr1[i];
arr1[i] = arr2[j];
arr2[j] = temp;
}
i--;
j++;
}
// Sort both arrays
Arrays.sort(arr1);
Arrays.sort(arr2);
}
}
def mergeArrays(arr1, arr2):
n = len(arr1)
m = len(arr2)
i = n - 1
j = 0
# Swap elements if needed
while i >= 0 and j < m:
if arr1[i] > arr2[j]:
arr1[i], arr2[j] = arr2[j], arr1[i]
i -= 1
j += 1
# Sort both arrays
arr1.sort()
arr2.sort()
using System;
class GfG {
public void mergeArrays(int[] arr1, int[] arr2){
int n = arr1.Length, m = arr2.Length;
int i = n - 1, j = 0;
// Swap elements if needed
while (i >= 0 && j < m){
if (arr1[i] > arr2[j]){
int temp = arr1[i];
arr1[i] = arr2[j];
arr2[j] = temp;
}
i--;
j++;
}
// Sort both arrays
Array.Sort(arr1);
Array.Sort(arr2);
}
}
function mergeArrays(arr1, arr2) {
let n = arr1.length;
let m = arr2.length;
let i = n - 1;
let j = 0;
// Swap elements if needed
while (i >= 0 && j < m) {
if (arr1[i] > arr2[j]) {
let temp = arr1[i];
arr1[i] = arr2[j];
arr2[j] = temp;
}
i--;
j++;
}
// Sort both arrays
arr1.sort((a, b) => a - b);
arr2.sort((a, b) => a - b);
}
Classical Problems on Two Pointer:
- Check if a string is Palindrome
- Reverse an array
- Dutch National Flag (DNF) Algorithm
- 2-Sum (sorted array / count all distinct pairs / closest to target)
- Check subsequence of a string
- Move zeros to end
- 3-Sum / Count distinct triplets / Closest to target
- Count possible triangles
- 4-Sum
- Trapping Rainwater Problem
Basics of Sliding Window
Sliding Window is a technique for problems involving contiguous subarrays or substrings.
Instead of recalculating the result from scratch for each window, we:
- Add the incoming element
- Remove the outgoing element
- Update our answer in O(1) time per shift
Types:
- Fixed Window — Window size k (e.g., Maximum sum in size-k subarray)
- Variable Window — Window expands/contracts to meet conditions (e.g., Longest Substring Without Repeating Characters)
Sliding Window Algorithm – O(n) Time
Example: Maximum Sum in K Size Subarray
Consider an array arr[] = [5, 2, -1, 0, 3] and value of k = 3 and n = 5
This is the initial phase where we have calculated the initial window sum starting from index 0 . At this stage the window sum is 6. Now, we set the maximum_sum as current_window i.e 6.

Now, we slide our window by a unit index. Therefore, now it discards 5 from the window and adds 0 to the window. Hence, we will get our new window sum by subtracting 5 and then adding 0 to it. So, our window sum now becomes 1. Now, we will compare this window sum with the maximum_sum. As it is smaller, we won't change the maximum_sum.

Similarly, now once again we slide our window by a unit index and obtain the new window sum to be 2. Again we check if this current window sum is greater than the maximum_sum till now. Once, again it is smaller so we don't change the maximum_sum.
Therefore, for the above array our maximum_sum is 6.

Algorithm:
- Compute sum of first k elements.
- Slide the window: subtract outgoing element, add incoming element.
- Track maximum sum.
int maxSubarraySum(vector<int>& arr, int k) {
int n = arr.size();
if (n < k) return -1;
// compute sum of first window
int windowSum = 0;
for (int i = 0; i < k; i++) {
windowSum += arr[i];
}
int maxSum = windowSum;
// slide the window
for (int i = k; i < n; i++) {
windowSum += arr[i] - arr[i - k];
maxSum = max(maxSum, windowSum);
}
return maxSum;
}
class GfG {
static int maxSubarraySum(int[] arr, int k) {
int n = arr.length;
if (n < k) return -1;
// compute sum of first window
int windowSum = 0;
for (int i = 0; i < k; i++) {
windowSum += arr[i];
}
int maxSum = windowSum;
// slide the window
for (int i = k; i < n; i++) {
windowSum += arr[i] - arr[i - k];
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
}
def maxSubarraySum(arr, k):
n = len(arr)
if n < k:
return -1
# compute sum of first window
windowSum = sum(arr[:k])
maxSum = windowSum
# slide the window
for i in range(k, n):
windowSum += arr[i] - arr[i - k]
maxSum = max(maxSum, windowSum)
return maxSum
class GfG {
static int maxSubarraySum(int[] arr, int k) {
int n = arr.Length;
if (n < k) return -1;
// compute sum of first window
int windowSum = 0;
for (int i = 0; i < k; i++) {
windowSum += arr[i];
}
int maxSum = windowSum;
// slide the window
for (int i = k; i < n; i++) {
windowSum += arr[i] - arr[i - k];
maxSum = Math.Max(maxSum, windowSum);
}
return maxSum;
}
}
function maxSubarraySum(arr, k) {
let n = arr.length;
if (n < k) return -1;
// compute sum of first window
let windowSum = 0;
for (let i = 0; i < k; i++) {
windowSum += arr[i];
}
let maxSum = windowSum;
// slide the window
for (let i = k; i < n; i++) {
windowSum += arr[i] - arr[i - k];
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
Classical Problems on Sliding Window:
- Maximum sum in k size subarray
- XOR of every k size subarray
- Number of distinct elements in window size k
- Longest subarray with at most two distinct integers
- Count subarrays with sum = X (positive a[i])
- Maximum consecutive ones after at most k flips
- Count subarrays with k odd numbers
- Count subarrays with at most k distinct elements
- Minimum removals to make target sum
- Smallest window containing all characters of another string
- Count substrings with exactly k distinct characters