Two Sum
Kamu mendapatkan array bilangan bulat nums dan bilangan bulat target. Tepat dua elemen nums pada posisi yang berbeda jika dijumlahkan menghasilkan target. Kembalikan indeks kedua elemen tersebut, dengan indeks yang lebih kecil terlebih dahulu.
Fungsi
- numsinteger-array
- array bilangan bulat yang akan dicari
- targetinteger
- jumlah yang harus dicapai oleh kedua entri
- Mengembalikaninteger-array
- kedua indeks, yang lebih kecil terlebih dahulu
Batasan
2 ≤ nums.length ≤ 104-109 ≤ nums[i] ≤ 109-109 ≤ target ≤ 109- Tepat satu pasangan posisi yang berbeda memiliki jumlah
target.
Contoh
- Input
- nums = [3, 8, 12, 5]target = 17
- Output
- [2, 3]
- Penjelasan
- 12 berada di indeks 2 dan 5 di indeks 3, dan 12 + 5 = 17. Tidak ada pasangan lain yang jumlahnya mencapai 17.
- Input
- nums = [6, 1, 4, 10]target = 7
- Output
- [0, 1]
- Penjelasan
- 6 pada indeks 0 dan 1 pada indeks 1 jika dijumlahkan menjadi 7: pasangan ini dapat menjadi dua entri pertama.
- Input
- nums = [2, -6, 9, 4, 13]target = 3
- Output
- [1, 2]
- Penjelasan
- -6 pada indeks 1 dan 9 pada indeks 2 jika dijumlahkan hasilnya 3. Bilangan negatif berpasangan dengan cara yang sama seperti bilangan positif.
Pertanyaan lanjutan
Jika nums sudah terurut, bisakah kamu menemukan pasangan tersebut dalam waktu O(n) dengan hanya O(1) memori tambahan?
Petunjuk
Buka satu per satu. Setiap petunjuk mengungkap sedikit lebih banyak.
Mencoba setiap pasangan dengan dua perulangan bersarang memang benar, tetapi untuk 10.000 angka, jumlahnya sekitar 50 juta pemeriksaan. Bisakah kamu menemukan pasangan setiap angka tanpa memindai list lagi?
Saat kamu berada pada nilai
x, kamu sudah tahu nilai yang akan melengkapi pasangan itu: target dikurangix. Satu-satunya pertanyaan adalah apakah kamu sudah menemukan nilai itu sebelumnya, dan pada indeks berapa.Telusuri list sekali dan simpan hash map yang memetakan setiap nilai yang sudah kamu lewati ke indeksnya. Di setiap posisi, cari dulu pasangan yang belum ada. Jika pasangan itu ada di map, kamu sudah mendapatkan kedua indeksnya. Jika tidak, simpan nilai saat ini lalu lanjutkan. Mencari sebelum menyimpan adalah hal yang mencegah sebuah angka berpasangan dengan dirinya sendiri.
Solusi
Memeriksa setiap pasangan bisa dilakukan, tetapi jumlah pekerjaan bertambah seiring kuadrat panjangnya. Balik pertanyaannya: saat berada pada angka x, kamu sudah tahu bahwa pasangannya pasti target - x. Hash map memberitahumu dalam waktu konstan apakah kamu sudah melewati nilai itu, sehingga satu kali penelusuran sudah cukup.
Periksa setiap pasangan
Benar, tetapi tidak selesai pada tes terbesar
Intuisi
Tetapkan satu indeks awal i, lalu coba setiap indeks j di sebelah kanannya sampai nums[i] + nums[j] sama dengan target. Memulai j dari i + 1 mencegah suatu posisi dipasangkan dengan dirinya sendiri, mencoba setiap pasangan satu kali, dan menempatkan indeks yang lebih kecil terlebih dahulu. Pasangan yang kamu cari termasuk salah satu pasangan yang kamu coba, jadi kamu akan menemukannya.
n angka membentuk sekitar n²/2 pasangan: n = 10^4 berarti hampir 5 × 10^7 penjumlahan.
Algoritma
- Lakukan perulangan
ipada setiap indeksnums. - Untuk setiap
i, lakukan perulanganjdarii + 1hingga indeks terakhir. - Jika
nums[i] + nums[j]sama dengantarget, kembalikan[i, j]. - Jika kedua perulangan selesai, kembalikan array kosong. Soal ini menjamin hal tersebut tidak akan terjadi.
def twoSum(nums, target):
n = len(nums)
for i in range(n):
# Only look at partners to the right, so each pair is checked once.
for j in range(i + 1, n):
if nums[i] + nums[j] == target:
return [i, j]
return []Satu kali iterasi dengan hash map
Intuisi
Untuk nums[i] yang tetap, perulangan bagian dalam pada pendekatan brute force mencari satu nilai yang sudah kamu ketahui sebelumnya: target - nums[i]. Pemindaian itu sebenarnya adalah pencarian, dan hash map yang memetakan nilai ke indeks melakukan pencarian dalam waktu konstan secara rata-rata.
Cari terlebih dahulu, simpan setelahnya. Dengan begitu, sebuah angka hanya bisa dipasangkan dengan angka yang muncul sebelumnya, tidak pernah dengan dirinya sendiri, dan karena pasangannya selalu muncul lebih awal, indeksnya berada di urutan pertama. Setiap angka dikunjungi sekali dengan operasi map yang membutuhkan waktu konstan, jadi pencariannya berkompleksitas O(n); biayanya adalah map dengan hingga n entri.
Algoritma
- Buat map kosong dari nilai ke indeks.
- Untuk setiap indeks
i, hitungneed, nilai yang melengkapi pasangan:targetdikuranginums[i]. - Jika
needada di dalam map, kembalikan indeks yang tersimpan, diikutii. - Jika tidak, simpan
nums[i]dengan indeksi, lalu lanjutkan.
def twoSum(nums, target):
seen = {}
for i, num in enumerate(nums):
need = target - num
if need in seen:
return [seen[need], i]
seen[num] = i
return []
Jebakan dan kasus tepi
- Menyimpan angka sebelum mencari pasangannya. Dengan
[4, 2, 6]dantarget = 8, angka 4 menemukan dirinya sendiri dan kamu mengembalikan[0, 0]. - Mengembalikan indeks dalam urutan yang salah. Jika pencarian dilakukan sebelum penyimpanan, indeks dari map adalah yang lebih kecil dan harus diletakkan lebih dulu.
- Mengurutkan array untuk menggunakan dua pointer, lalu mengembalikan posisi dari salinan yang sudah diurutkan. Simpan indeks asli di samping setiap nilai.
- Mengasumsikan nilainya positif atau berbeda.
[0, 7, -3, 0]dengantarget = 0memasangkan kedua angka nol:[0, 3]. - Dalam Lua dan R, mengembalikan indeks berbasis 1. Kurangi masing-masing dengan 1.
Pertanyaan yang sering diajukan3
Berapa kompleksitas waktu Two Sum?
Solusi hash map berjalan dalam waktu O(n), karena solusi ini mengunjungi setiap angka satu kali dan setiap pencarian atau penyisipan membutuhkan waktu konstan secara rata-rata. Solusi ini menggunakan ruang tambahan O(n) untuk map. Memeriksa setiap pasangan membutuhkan waktu O(n²) dan ruang O(1).
Bisakah Two Sum diselesaikan tanpa ruang tambahan?
Tidak dalam waktu linear pada array yang tidak terurut. Dengan ruang tambahan O(1), kamu kembali harus memeriksa setiap pasangan, yang membutuhkan waktu O(n²). Hash map menukar penggunaan memori O(n) dengan waktu linear.
Bagaimana Two Sum menangani angka duplikat?
Duplikat berfungsi saat kamu mencari pasangannya sebelum menyimpan angka saat ini. Dalam [7, 3, 7] dengan target = 14, angka 7 pertama disimpan pada indeks 0 dan angka 7 kedua menemukannya, sehingga menghasilkan [0, 2]. Satu angka 7 saja tidak pernah berpasangan dengan dirinya sendiri: angka itu belum ada di map saat kamu mencarinya.
Soal serupa
Soal yang memakai ide yang sama. Mengerjakan dua atau tiga di antaranya membuat polanya melekat.
def twoSum(nums, target):
# Tulis kodemu di siniTes #1
Tes #2
Tes #3
Argumen
nums = [3, 8, 12, 5] target = 17
Output yang diharapkan
[2, 3]