لو بتحل مسألة على array مرتّب وبتلاقي نفسك بتكتب nested loop، فيه احتمال كبير إن Two Pointers يخلّي الكود يشتغل في O(N) بدل O(N²) — يعني على array بمليون عنصر، بدل دقايق تبقى مللي ثواني.
المشكلة باختصار
كل مبرمج بيقابل مسائل array من نوع: "لاقي عنصرين مجموعهم يساوي target"، أو "اعكس string"، أو "احذف التكرارات من array مرتّب". الحل البديهي بيبقى loop جوّه loop — لكل عنصر، دوّر على باقي العناصر. ده O(N²)، يعني لو الـ array فيه 100 ألف عنصر، الكود بياخد 10 مليار عملية. على CPU عادي، ده ثواني طويلة، مش جزء من ثانية.
Two Pointers نمط بسيط بيحل نسبة كبيرة من المسائل دي في pass واحد على الـ array، يعني O(N). الفكرة كلها مش هياكل بيانات معقّدة، فيها بس مؤشرين بيتحركوا بقواعد ذكية.
الفكرة بمثال بسيط جدًا
تخيّل صف طويل عند بوّابة المطار. الناس مرتبين بأرقام تذاكرهم — الأصغر في الأول، الأكبر في الآخر. مديرك طلب منك تلاقي راكبَين مجموع أرقام تذاكرهم بالظبط 100.
الطريقة الأولى: تمشي على كل راكب وتسأله عن كل واحد بعده — ده ممكن ياخد ساعات. الطريقة الذكية: تحطّ موظف في أول الصف وموظف في آخر الصف. الموظفين يجمعوا الرقمين اللي قدامهم:
- لو المجموع = 100 → لقيتهم وخلصت.
- لو المجموع أقل من 100 → موظف الأول يتقدّم خطوة (لأن العنصر الأكبر اللي يليه هيكبّر المجموع).
- لو المجموع أكبر من 100 → موظف الآخر يرجع خطوة (لأن العنصر الأصغر اللي يسبقه هيصغّر المجموع).
الموظفين هيتقابلوا في النص بعد عدد خطوات مساوي لطول الصف. ده بالظبط Two Pointers.
التعريف الدقيق
Two Pointers نمط برمجي بنحط فيه مؤشرَين (index variables) على array أو string، ثم نحرّكهم حسب شرط محدد. الشكلين الأكثر استخدامًا:
- Opposite ends: مؤشر بيبدأ من الـ index صفر، الآخر من
n-1، يتحرّكوا تجاه بعض. بنستخدمه لما الـ array مرتّب. - Same direction (Fast & Slow): المؤشرين بيبدآ من نفس النقطة، واحد بيتحرّك أسرع من التاني. بنستخدمه لكشف التكرارات أو الـ cycles داخل linked list.
الشرط الأساسي عشان النمط يشتغل: كل تحريك لمؤشر لازم يكون مبني على معلومة محسومة من المقارنة الحالية. لو المنطق مش محسوم، النمط مش هيوفرلك حاجة وبتحتاج hashmap أو dynamic programming.
كود شغّال: Two Sum على array مرتّب
الحل البديهي O(N²) — nested loop:
def two_sum_naive(arr, target):
n = len(arr)
for i in range(n):
for j in range(i + 1, n):
if arr[i] + arr[j] == target:
return [i, j]
return []