Meta 2023 Mülakat Sorusu Çözümü
JavaScript'te bir dizide tekrar eden eleman bulmak, yazılım mülakatlarında sık karşılaşılan klasik bir problemdir. Bunu yapmanın birden fazla yolu var; ancak en yaygın ve verimli yöntem Hash Map kullanmaktır. Bir nesne ({}), her elemanı anahtar olarak kaydeder ve daha önce görülüp görülmediğini sabit sürede (O(1)) kontrol etmeyi sağlar. Bu yaklaşım, iç içe döngülerle yazılan O(n²) çözümlerin aksine diziyi tek geçişte tarar.
Aşağıdaki JavaScript kodunu inceleyin. nums = [1, 3, 4, 2, 3] dizisi verildiğinde console.log ne yazdırır?
function check(nums) {
let seen = {}
for (let n of nums) {
if (seen[n]) return n
seen[n] = true
}
}
console.log(check([1, 3, 4, 2, 3]))
Seçenekler: A) 1 B) 2 C) 3 D) 4
Cevabı düşünmek için bir dakikanızı ayırın, ardından aşağıya bakın.
Cevap: C) 3
Adım Adım Çözüm
1. Fonksiyon Ne Yapıyor?
check(nums) fonksiyonunun amacı basit: verilen bir dizide ilk tekrar eden elemanı bul ve döndür.
Bunu yapmak için seen adında boş bir JavaScript nesnesi ({}) kullanıyor. Bu nesne bir tür kayıt defteri gibi davranıyor: döngü ilerledikçe her elemanı bu deftere not alıyor. Eğer bir elemanla karşılaştığında defterde zaten kayıtlıysa, o elemanı hemen döndürüp fonksiyonu sonlandırıyor.
let seen = {} // Boş kayıt defteri
seen[3] = true // "3'ü gördük" diye not al
if (seen[3]) return 3 // "3'ü daha önce gördük, döndür"
2. for...of Döngüsü Nasıl Çalışıyor?
for (let n of nums) ifadesi diziyi soldan sağa doğru tek tek geziyor. Her turda n değişkeni sıradaki elemanı alıyor:
- tur →
n = 1 - tur →
n = 3 - tur →
n = 4 - tur →
n = 2 - tur →
n = 3
Döngü her adımda şu iki soruyu soruyor:
seen[n]daha önce kaydedildi mi?- Kaydedilmediyse
seen[n] = trueyap ve devam et.
3. Diziyi Adım Adım İzleyelim
nums = [1, 3, 4, 2, 3] dizisiyle döngü başlıyor, seen = {} ile boş başlıyoruz:
| Adım | n | seen[n] var mı? | İşlem | seen durumu |
|---|---|---|---|---|
| 1 | 1 | Yok | seen[1] = true | { 1: true } |
| 2 | 3 | Yok | seen[3] = true | { 1: true, 3: true } |
| 3 | 4 | Yok | seen[4] = true | { 1: true, 3: true, 4: true } |
| 4 | 2 | Yok | seen[2] = true | { 1: true, 3: true, 4: true, 2: true } |
| 5 | 3 | Var! | return 3 → fonksiyon durdu | — |
- adımda
n = 3geldiğindeseen[3]zatentrueolduğu içinif (seen[n])koşulu sağlanır. Fonksiyon3değerini döndürür ve döngü tamamen durur. 6. adım hiç çalışmaz.
4. Neden Diğer Şıklar Yanlış?
| Şık | Değer | Neden yanlış? |
|---|---|---|
| A | 1 | Dizide yalnızca 1. sırada geçiyor, hiç tekrar etmiyor |
| B | 2 | Dizide yalnızca 4. sırada geçiyor, hiç tekrar etmiyor |
| C | 3 | Hem 2. hem 5. sırada — ilk tekrar eden eleman |
| D | 4 | Dizide yalnızca 3. sırada geçiyor, hiç tekrar etmiyor |
Kullanılan Konsept: Hash Map
Bu çözüm klasik bir Hash Map (ya da JavaScript'te nesne tabanlı arama) tekniğidir.
Neden bu yöntem tercih edilir?
Bir dizide tekrar eden elemanı bulmanın en saf yolu iki iç içe döngü yazmaktır: her elemanı diğer tüm elemanlarla karşılaştırırsınız. Bu çalışır; ama dizi büyüdükçe işlem sayısı hızla artar — 1000 elemanlı dizide yaklaşık 1.000.000 karşılaştırma yapmanız gerekir. Buna O(n²) denir.
Hash Map yöntemi ise her elemanı yalnızca bir kez kontrol eder. 1000 elemanlı dizide sadece 1000 adım yeterlidir. Buna O(n) denir.
// Yavaş yöntem — O(n²)
for (let i = 0; i < nums.length; i++) {
for (let j = i + 1; j < nums.length; j++) {
if (nums[i] === nums[j]) return nums[i]
}
}
// Hızlı yöntem — O(n), kodumuzda kullanılan
let seen = {}
for (let n of nums) {
if (seen[n]) return n
seen[n] = true
}
Bellek - Hız Dengesi
Hash Map yöntemi hız kazanmak için ekstra bellek kullanır: seen nesnesi her elemanı kaydederek büyür. Bu, yazılımda sık karşılaşılan bir zaman-bellek dengesi (time-space tradeoff) örneğidir. Çoğu durumda bu değiş tokuş tercih edilir çünkü bellek ucuzdur, zaman değil.
Özet
check()fonksiyonu bir dizide ilk tekrar eden elemanı döndürür.- Bunu
seennesnesiyle O(n) zaman karmaşıklığıyla yapar. [1, 3, 4, 2, 3]dizisinde3hem 2. hem 5. sırada geçtiği için cevap 3'tür.returnifadesi çalışır çalışmaz fonksiyon durur; döngünün kalanı hiç çalışmaz.