Find Peak Element
nums dizisi önce yükselir, sonra düşer: bir indekse kadar her değer kendisinden önceki değerden büyüktür ve bu indeksten sonraki her değer kendisinden önceki değerden küçüktür. Her iki bölümden biri boş olabilir; bu nedenle dizi yalnızca yükselebilir veya yalnızca düşebilir. Dönüş indeksindeki değer tepedir; komşularının her birinden büyük olan tek değerdir.
Tepe değerinin indeksini O(log n) zamanda döndürün.
Fonksiyon
- numsinteger-array
- değerler bir tepe noktasına yükselir ve ardından düşer
- Döndürürinteger
- tepenin indeksi
Kısıtlar
1 ≤ nums.length ≤ 5000-106 ≤ nums[i] ≤ 106nums[i] != nums[i+1]her geçerliiiçin.numsbir indekse kadar kesin artar ve o indeksten sonra kesin azalır; dolayısıyla tam olarak bir tepe noktası vardır.
Örnekler
- Girdi
- nums = [2, 5, 9, 4, 1]
- Çıktı
- 2
- Açıklama
- Değerler 2, 5 ve 9 üzerinden yükselir, ardından 4 ve 1 üzerinden düşer. Dönüş noktası 9, indeks 2'dir.
- Girdi
- nums = [8, 6, 3, -2]
- Çıktı
- 0
- Açıklama
- Dizi yalnızca azalan sırada olduğundan tırmanış kısmı boştur ve tepe noktası ilk değer olan, 0. indisteki 8'dir.
- Girdi
- nums = [-7, -3, 0, 12, 40]
- Çıktı
- 4
- Açıklama
- Dizi yalnızca yükseliyor, bu yüzden tepe noktası son değerdir: 4. indisteki 40. Negatif değerler hiçbir şeyi değiştirmez.
Ek soru
Komşu hücrelerden hiçbirinin eşit olmadığı bir ızgarada, tepe bir hücrenin en fazla dört komşusundan daha büyük olmasıdır. Her hücreyi okumadan bir tepe bulabilir misin?
İpuçları
Tek tek açın. Her biri biraz daha fazlasını gösterir.
Herhangi bir
midindeksi seç venums[mid+1]değerine bak. Bu adımın yönü, zirvenin nerede olduğu hakkında sana ne söyler?Yukarı adım yalnızca zirveden önce, aşağı adım ise yalnızca zirvede veya zirveden sonra gerçekleşir. Dolayısıyla bir karşılaştırma,
middeğerinin bir tarafını eler.Tepe noktasını her zaman içeren bir aralık tut. Yukarı adımda
lodeğerinimid+1konumuna taşı; aksi haldehideğerinimidkonumuna taşı. Birbirlerine ulaşınca dur.
Çözüm
Tek bir tepe olduğunda, tepe en büyük değerdir; bu nedenle tek bir geçişte O(n) içinde bulunur. O(log n) için nums[mid] ile nums[mid+1] değerlerini karşılaştır: mid noktasındaki eğim, tepenin hangi tarafında olduğunu gösterir; böylece her adımda aralığın yarısı elenebilir.
Değerler düşmeye başlayana kadar yürü
Sezgi
Zirveden önce her değer bir sonrakinden küçüktür ve zirveden itibaren her değer daha büyüktür. Bu yüzden zirve, nums[i] > nums[i+1] koşulunu sağlayan ilk i indeksidir veya dizi yalnızca yükseliyorsa son indekstir.
Zirve 5000 değerin sonunda olduğunda, yürüyüş 4999 karşılaştırma yapar; ikili arama ise 13 karşılaştırma gerektirir.
Algoritma
- 0'dan
n-2'ye kadariiçin,nums[i]ilenums[i+1]'i karşılaştır. nums[i]'nin daha büyük olduğu ilkideğerinde,i'yi döndür.- Döngü bir düşüş olmadan sona ererse,
n-1'i döndür.
def findPeakElement(nums):
for i in range(len(nums) - 1):
if nums[i] > nums[i + 1]:
return i # the first step down starts at the peak
return len(nums) - 1 # never went down: the last value is the peakEğim üzerinde ikili arama
Sezgi
Bir çifti, nums[mid] ve nums[mid+1] değerlerini okuyun. Yükselen bir adım, dizinin hâlâ yükseldiği anlamına gelir; bu dizide bu yalnızca zirveden önce gerçekleşir: zirve mid+1 konumundadır veya onun sağındadır. Alçalan bir adım, zirvede ya da zirveyi geçmiş olduğunuz anlamına gelir: zirve mid konumundadır veya onun solundadır.
Zirveyi her zaman içeren bir [lo, hi] aralığını koruyun. Yükselen bir adımda lo değerini mid+1 konumuna taşıyın. Alçalan bir adımda hi değerini mid konumuna taşıyın; zirve olabileceği için mid değerini aralıkta tutun. lo ile hi eşitlendiğinde geriye kalan tek indeks zirvedir. mid değerini aşağı yuvarlamak onun hi değerinden küçük kalmasını sağlar; böylece mid+1 her zaman vardır.
İlk örnekte, mid = 2 iken 9 > 4 görülür, bu yüzden hi = 2 olur; ardından mid = 1 iken 5 < 9 görülür, bu yüzden zirve olan lo = 2 olur. 5000 değer en fazla 13 adım gerektirir.
Algoritma
lo = 0vehi = n-1değerlerini ayarla.lo < hiolduğu sürecemid = lo + (hi - lo) / 2değerini hesapla ve aşağı yuvarla.nums[mid] < nums[mid+1]iselo = mid + 1değerini ayarla.- Aksi takdirde
hi = middeğerini ayarla. lodeğerini döndür.
def findPeakElement(nums):
lo, hi = 0, len(nums) - 1 # the peak is always inside [lo, hi]
while lo < hi:
mid = lo + (hi - lo) // 2 # mid < hi, so mid + 1 is a valid index
if nums[mid] < nums[mid + 1]:
lo = mid + 1 # still climbing: the peak is to the right of mid
else:
hi = mid # going down: the peak is mid or to its left
return lo
Tuzaklar ve uç durumlar
- Bir aşağı adımda
hi = mid - 1ayarlamak.[2, 5, 9, 4, 1]içinde ilkmidtepe noktasının kendisidir vehi = 1bu noktayı aralıktan çıkarır; arama 1 sonucunu döndürür. middeğerini aşağı yuvarlarkennums[mid-1]ile karşılaştırmak.mid0 olabilir; bu durumda sol komşu yoktur.hi = nile yarı açık aralık kullanmak. Böylecemidn-1olabilir venums[mid+1]dizinin sonunun ötesini okur; tek bir değer için bu hemen gerçekleşir.- Lua ve R'de kaydırmayı unutmak. Yanıt hâlâ 0 tabanlı indekstir, bu nedenle
ikonumui-1olarak döndürülür.
Sıkça sorulan sorular3
Find Peak Element'ın zaman karmaşıklığı nedir?
İkili arama O(log n) zamanda ve O(1) alan kullanarak çalışır; 5000 değer için en fazla 13 adım sürer. Soldan ilerlemek O(n) zaman alır, çünkü düşüşü bulmadan önce her çifti okuyabilir.
Birden fazla tepe noktası olduğunda ikili arama yine de çalışır mı?
Evet, komşular birbirinden farklı olduğu ve her iki ucun ötesindeki noktalar tüm değerlerden daha düşük sayıldığı sürece. En yüksek olanı değil, bir tepe döndürür. Bir yükseliş adımından sonra değerler en geç aralığın sonuna kadar düşüşe geçmelidir ve ilk dönüş bir tepe olduğundan, aramanın tuttuğu tarafta her zaman bir tepe bulunur.
Tepe noktası her zaman en büyük değer midir?
Bu problemde evet: dizi tek bir tepe noktasına kadar yükselir ve sonra alçalır, dolayısıyla başka hiçbir değer daha büyük olamaz. Birden fazla tepe noktasının olduğu sürümde ise durum böyle değildir; çünkü her iki komşusundan da büyük olan herhangi bir değer tepe noktası sayılır. Aramanın maksimum değeri bulmak yerine komşuları karşılaştırmasının nedeni budur.
Benzer problemler
Aynı fikirleri kullanan problemler. İki üçünü çözmek bir kalıbı kalıcı hale getirir.
def findPeakElement(nums):
# Kodu buraya yazınTest #1
Test #2
Test #3
Argüman
nums = [2, 5, 9, 4, 1]
Beklenen Çıktı
2