Kembali ke jurnalCATATAN FAJAR
Algorithms2 menit baca

Teknik Fast and Slow Pointers

Pakai dua pointer dengan kecepatan berbeda untuk mendeteksi cycle tanpa menyimpan kumpulan node yang udah dikunjungi.

Di artikel ini 3 bagian

Mendeteksi cycle di linked list nggak perlu menyimpan setiap node yang udah dikunjungi. Metode fast and slow pointer dari Floyd cuma memakai dua reference dan O(1) extra space. Waktu pertama kali lihat metode ini, saya nggak menyangka dua reference aja udah cukup.

Mendeteksi cycle tanpa set

Cycle terjadi ketika sebuah node menunjuk balik ke node sebelumnya, sehingga kalau kita mengikuti link next, kita nggak akan pernah sampai ke null. Tugasnya adalah mengembalikan true kalau ada cycle dan false untuk list yang punya ujung. Awalnya saya pakai Set untuk mencatat node yang udah dikunjungi:

javascript
function hasCycleNaive(head) {
  let seen = new Set();

  while (head !== null) {
    if (seen.has(head)) {
      return true; // Found a cycle!
    }
    seen.add(head);
    head = head.next;
  }

  return false; // No cycle
}

Metode berbasis set ini benar, tapi set-nya ikut membesar seiring panjang list, jadi extra space-nya O(n).

Metode two pointer dari Floyd

Lalu saya belajar teknik fast and slow pointers. Satu pointer bergerak satu node setiap langkah, sementara yang lain bergerak dua. Kalau list-nya punya ujung, fast atau fast.next bakal sampai ke null. Kalau list-nya berputar, kedua pointer masuk ke cycle, dan pointer yang lebih cepat akhirnya menyusul yang lebih lambat. Implementasinya:

javascript
function hasCycle(head) {
  if (head === null || head.next === null) {
    return false; // An empty list or a null next link cannot form a cycle
  }

  let slow = head; // Moves 1 step at a time
  let fast = head.next; // Moves 2 steps at a time

  while (fast !== null && fast.next !== null) {
    if (slow === fast) {
      return true; // They met! There's a cycle
    }
    slow = slow.next; // Move slow pointer 1 step
    fast = fast.next.next; // Move fast pointer 2 steps
  }

  return false; // Fast pointer hit null, no cycle
}

Begitu kedua pointer ada di dalam cycle, posisi mereka berulang modulo panjang cycle. Pointer cepat mendekat satu node ke pointer lambat di setiap iterasi, jadi jarak relatif mereka akhirnya jadi nol. Pengecekan null menangani list tanpa cycle sebelum salah satu pointer di-dereference.

Kompleksitas dan penerapannya

Saya kaget waktu tahu ide yang sama juga berguna di luar linked list:

  • Verifikasi symlink: Mendeteksi symbolic link yang melingkar di file system
  • Pengecekan dependency di compiler: Cek apakah ada cycle ketika setiap module dalam urutan cuma punya satu dependency berikutnya

Loop pointer-nya butuh O(n) time. Extra space-nya O(1). Algoritma ini memanfaatkan cycle itu sendiri, bukan set terpisah untuk node yang udah dikunjungi.

Fast and slow pointers layak jadi pilihan default setiap kali sebuah urutan mungkin berputar dan setiap langkahnya bisa dihitung dari posisi saat ini. Teknik ini mengganti penyimpanan state kunjungan sebesar O(n) dengan sejumlah pointer yang konstan.

TOPIK

MAKASIH UDAH BACA

Gimana menurutmu?

Reaksi atau obrolan, dua-duanya selalu ditunggu.

Memuat reaksi…

Bagikan

Memuat komentar...

LANJUT JELAJAH

Satu pikiran bawa ke pikiran lain.

Semua tulisan
Kembali ke semua tulisanSatu catatan, pelan-pelan.