{
  "id": "arrays/two-pointers",
  "version": 1,
  "deterministic": true,
  "url": "/dsa/arrays/two-pointers",
  "topic": {
    "slug": "arrays",
    "title": "Arrays"
  },
  "title": "Two Pointers",
  "tagline": "Two markers moving toward each other turn an O(n²) search into O(n).",
  "vizKind": "array",
  "complexity": {
    "time": {
      "best": "O(1)",
      "average": "O(n)",
      "worst": "O(n)"
    },
    "space": "O(1)",
    "growth": "linear",
    "note": "One pass, because the two pointers only ever move toward each other — together they take at most n steps. That's down from O(n²) for checking every pair, and it uses no extra memory. The catch: the array must be sorted first."
  },
  "code": {
    "javascript": "function twoSum(a, target) {\n  let lo = 0;\n  let hi = a.length - 1;\n  while (lo < hi) {\n    const sum = a[lo] + a[hi];\n    if (sum === target) return [lo, hi];\n    if (sum < target) lo++;\n    else hi--;\n  }\n  return null;\n}",
    "python": "def two_sum(a, target):\n    lo = 0\n    hi = len(a) - 1\n    while lo < hi:\n        s = a[lo] + a[hi]\n        if s == target: return (lo, hi)\n        if s < target: lo += 1\n        else: hi -= 1\n\n    return None\n",
    "java": "int[] twoSum(int[] a, int target) {\n  int lo = 0;\n  int hi = a.length - 1;\n  while (lo < hi) {\n    int sum = a[lo] + a[hi];\n    if (sum == target) return new int[]{lo, hi};\n    if (sum < target) lo++;\n    else hi--;\n  }\n  return null;\n}",
    "cpp": "pair<int,int> twoSum(vector<int> a, int target) {\n  int lo = 0;\n  int hi = a.size() - 1;\n  while (lo < hi) {\n    int sum = a[lo] + a[hi];\n    if (sum == target) return {lo, hi};\n    if (sum < target) lo++;\n    else hi--;\n  }\n  return {-1, -1};\n}"
  },
  "defaultInput": [
    2,
    5,
    8,
    12,
    15,
    21,
    28
  ],
  "defaultTarget": 20,
  "inputHint": "The array is sorted for you. Find two values that add up to the target.",
  "pitfalls": [
    {
      "wrong": "Using two pointers on an unsorted array for pair-sum.",
      "right": "The technique relies on order: 'sum too small → move left up' is only valid because values are sorted. On unsorted data you'd need a different approach (like a hash set)."
    },
    {
      "wrong": "Moving both pointers on every step.",
      "right": "Move exactly one, chosen by the comparison. Moving both can skip right over the answer."
    },
    {
      "wrong": "Letting the pointers cross.",
      "right": "Stop as soon as lo meets or passes hi. Continue past that and you start re-examining pairs you've already ruled out."
    }
  ],
  "quiz": [
    {
      "q": "Why does the two-pointer pair-sum need a sorted array?",
      "options": [
        "So it looks neat",
        "So a too-small or too-big sum tells you exactly which pointer to move",
        "So there are no duplicates",
        "It doesn't — it works on any array"
      ],
      "answer": 1,
      "why": "Sorted order gives each comparison meaning: if the sum is too small, the only way to increase it is to move the left pointer to a bigger value. Without order, that logic falls apart."
    },
    {
      "q": "What does two pointers do to the time complexity of pair-sum?",
      "options": [
        "Keeps it at O(n²)",
        "Drops it from O(n²) to O(n)",
        "Raises it to O(n log n)",
        "Makes it O(1)"
      ],
      "answer": 1,
      "why": "Brute force checks every pair — O(n²). Two pointers make one pass because each pointer only moves inward, so together they cover the array once: O(n)."
    },
    {
      "q": "On each step, how many pointers do you move?",
      "options": [
        "Both",
        "Exactly one, chosen by the comparison",
        "Neither",
        "It depends on the array size"
      ],
      "answer": 1,
      "why": "You move exactly one pointer, decided by whether the sum was too small (move left up) or too big (move right down). Moving both risks stepping over the answer."
    }
  ],
  "problems": [
    {
      "name": "Two Sum II - Input Array Is Sorted",
      "difficulty": "Medium",
      "url": "https://leetcode.com/problems/two-sum-ii-input-array-is-sorted/"
    },
    {
      "name": "Valid Palindrome",
      "difficulty": "Easy",
      "url": "https://leetcode.com/problems/valid-palindrome/"
    },
    {
      "name": "Container With Most Water",
      "difficulty": "Medium",
      "url": "https://leetcode.com/problems/container-with-most-water/"
    }
  ],
  "trace": {
    "note": "Each frame is one immutable step: data snapshot, pointers, per-index roles, executing code line, and a one-sentence explanation.",
    "length": 9,
    "frames": [
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 0
          },
          {
            "name": "hi",
            "index": 6
          }
        ],
        "highlights": [],
        "codeLine": 1,
        "variables": {
          "target": 20
        },
        "explanation": "Find two values that add up to 20. The array is sorted, which is the key — it lets us start one pointer at each end and squeeze inward.",
        "stats": {
          "comparisons": 0,
          "swaps": 0
        },
        "accent": "active"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 0
          },
          {
            "name": "hi",
            "index": 6
          }
        ],
        "highlights": [
          {
            "index": 0,
            "role": "compare"
          },
          {
            "index": 6,
            "role": "compare"
          }
        ],
        "codeLine": 5,
        "variables": {
          "lo": 2,
          "hi": 28,
          "sum": 30,
          "target": 20
        },
        "explanation": "2 + 28 = 30. Too big.",
        "stats": {
          "comparisons": 1,
          "swaps": 0
        },
        "accent": "compare"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 0
          },
          {
            "name": "hi",
            "index": 5
          }
        ],
        "highlights": [
          {
            "index": 6,
            "role": "discarded"
          }
        ],
        "codeLine": 8,
        "variables": {
          "lo": 2,
          "hi": 21
        },
        "explanation": "The sum was too big, so move the right pointer left to a smaller value.",
        "stats": {
          "comparisons": 1,
          "swaps": 0
        },
        "accent": "active"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 0
          },
          {
            "name": "hi",
            "index": 5
          }
        ],
        "highlights": [
          {
            "index": 0,
            "role": "compare"
          },
          {
            "index": 5,
            "role": "compare"
          },
          {
            "index": 6,
            "role": "discarded"
          }
        ],
        "codeLine": 5,
        "variables": {
          "lo": 2,
          "hi": 21,
          "sum": 23,
          "target": 20
        },
        "explanation": "2 + 21 = 23. Too big.",
        "stats": {
          "comparisons": 2,
          "swaps": 0
        },
        "accent": "compare"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 0
          },
          {
            "name": "hi",
            "index": 4
          }
        ],
        "highlights": [
          {
            "index": 5,
            "role": "discarded"
          },
          {
            "index": 6,
            "role": "discarded"
          }
        ],
        "codeLine": 8,
        "variables": {
          "lo": 2,
          "hi": 15
        },
        "explanation": "The sum was too big, so move the right pointer left to a smaller value.",
        "stats": {
          "comparisons": 2,
          "swaps": 0
        },
        "accent": "active"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 0
          },
          {
            "name": "hi",
            "index": 4
          }
        ],
        "highlights": [
          {
            "index": 0,
            "role": "compare"
          },
          {
            "index": 4,
            "role": "compare"
          },
          {
            "index": 5,
            "role": "discarded"
          },
          {
            "index": 6,
            "role": "discarded"
          }
        ],
        "codeLine": 5,
        "variables": {
          "lo": 2,
          "hi": 15,
          "sum": 17,
          "target": 20
        },
        "explanation": "2 + 15 = 17. Too small.",
        "stats": {
          "comparisons": 3,
          "swaps": 0
        },
        "accent": "compare"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 1
          },
          {
            "name": "hi",
            "index": 4
          }
        ],
        "highlights": [
          {
            "index": 0,
            "role": "discarded"
          },
          {
            "index": 5,
            "role": "discarded"
          },
          {
            "index": 6,
            "role": "discarded"
          }
        ],
        "codeLine": 7,
        "variables": {
          "lo": 5,
          "hi": 15
        },
        "explanation": "The sum was too small, so move the left pointer right to a bigger value. We never need the old left value again.",
        "stats": {
          "comparisons": 3,
          "swaps": 0
        },
        "accent": "active"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 1
          },
          {
            "name": "hi",
            "index": 4
          }
        ],
        "highlights": [
          {
            "index": 1,
            "role": "compare"
          },
          {
            "index": 4,
            "role": "compare"
          },
          {
            "index": 0,
            "role": "discarded"
          },
          {
            "index": 5,
            "role": "discarded"
          },
          {
            "index": 6,
            "role": "discarded"
          }
        ],
        "codeLine": 5,
        "variables": {
          "lo": 5,
          "hi": 15,
          "sum": 20,
          "target": 20
        },
        "explanation": "5 + 15 = 20. That's the target!",
        "stats": {
          "comparisons": 4,
          "swaps": 0
        },
        "accent": "compare"
      },
      {
        "data": [
          {
            "id": "c0-2",
            "value": 2
          },
          {
            "id": "c1-5",
            "value": 5
          },
          {
            "id": "c2-8",
            "value": 8
          },
          {
            "id": "c3-12",
            "value": 12
          },
          {
            "id": "c4-15",
            "value": 15
          },
          {
            "id": "c5-21",
            "value": 21
          },
          {
            "id": "c6-28",
            "value": 28
          }
        ],
        "pointers": [
          {
            "name": "lo",
            "index": 1
          },
          {
            "name": "hi",
            "index": 4
          }
        ],
        "highlights": [
          {
            "index": 1,
            "role": "found"
          },
          {
            "index": 4,
            "role": "found"
          },
          {
            "index": 0,
            "role": "discarded"
          },
          {
            "index": 5,
            "role": "discarded"
          },
          {
            "index": 6,
            "role": "discarded"
          }
        ],
        "codeLine": 6,
        "variables": {
          "result": "5 + 15",
          "looks": 4
        },
        "explanation": "Found it: 5 + 15 = 20, in just 4 looks. Checking every pair would have taken far more.",
        "stats": {
          "comparisons": 4,
          "swaps": 0
        },
        "accent": "found"
      }
    ]
  }
}