Maximum Subarray
Kamu mendapatkan sebuah list bilangan bulat nums. Subarray adalah rangkaian elemen bersebelahan yang diambil tanpa jeda, dan harus berisi setidaknya satu elemen. Kembalikan jumlah terbesar yang bisa dimiliki subarray mana pun dari nums. Kamu hanya mengembalikan jumlahnya, bukan subarray itu sendiri.
Fungsi
- numsinteger-array
- daftar bilangan bulat, dengan setidaknya satu elemen
- Mengembalikaninteger
- jumlah terbesar dari rangkaian elemen bersebelahan yang tidak kosong
Batasan
1 ≤ nums.length ≤ 105-104 ≤ nums[i] ≤ 104- Jawabannya selalu muat dalam bilangan bulat bertanda 32-bit.
Contoh
- Input
- nums = [2, -4, 3, -1, 5, -6, 1]
- Output
- 7
- Penjelasan
- Perulangan
[3, -1, 5]berjumlah 7. Memperluasnya ke kiri menambahkan -4 lalu 2, sehingga totalnya berkurang 2. Memperluasnya ke kanan menambahkan -6 lalu 1, sehingga totalnya berkurang 5. Tidak ada perulangan lain yang hasilnya lebih baik.
- Input
- nums = [-3, -1, -2]
- Output
- -1
- Penjelasan
- Semua angka bernilai negatif, jadi rentang yang lebih panjang hanya akan mengurangi jumlahnya, dan rentang terbaik adalah satu elemen -1. Subarray tidak boleh kosong, jadi jawabannya adalah -1, bukan 0.
Pertanyaan lanjutan
Bisakah kamu juga menyelesaikannya dengan strategi bagi dan taklukkan dalam O(n log n), membagi list menjadi dua dan menangani rangkaian yang melintasi bagian tengah?
Petunjuk
Buka satu per satu. Setiap petunjuk mengungkap sedikit lebih banyak.
Fokus pada rentetan yang berakhir tepat di satu posisi. Bagaimana rentetan terbaik yang berakhir di sini berkaitan dengan rentetan terbaik yang berakhir di posisi tepat sebelumnya?
Deretan yang berakhir pada elemen saat ini bisa melanjutkan deretan yang berakhir tepat sebelumnya atau dimulai dari awal pada elemen ini. Melanjutkannya hanya membantu jika jumlah deretan sebelumnya positif.
Telusuri list satu kali dan simpan dua angka: jumlah terbaik dari perulangan yang berakhir di elemen saat ini, dan jumlah terbaik yang ditemukan sejauh ini. Mulai keduanya dari elemen pertama, agar list yang hanya berisi angka negatif tetap menghasilkan elemen terbesarnya.
Solusi
Sebuah list berisi n angka memiliki sekitar n²/2 subarray, terlalu banyak untuk diperiksa satu per satu jika ada 10^5 elemen. Bagian tersulit adalah angka negatif: suatu rangkaian harus mempertahankan elemen negatif jika angka setelahnya bisa mengimbanginya, dan membuang semua elemen sebelumnya jika tidak. Algoritma Kadane membuat pilihan itu pada setiap elemen dengan satu perbandingan.
Jumlahkan setiap subarray
Benar, tetapi tidak selesai pada tes terbesar
Intuisi
Setiap subarray memiliki indeks pertama left dan indeks terakhir right, jadi mencoba setiap pasangan akan menemukan yang terbaik. Tetapkan left lalu geser right ke depan, sambil menambahkan setiap elemen baru ke total yang terus diperbarui: setiap subarray hanya memerlukan satu penjumlahan, tanpa perulangan ketiga.
Namun, masih ada sekitar n²/2 pasangan, yaitu lima miliar penjumlahan untuk 10^5 elemen.
Algoritma
- Atur
bestke elemen pertama. - Untuk setiap indeks awal
left, aturtotalyang terus diperbarui ke 0. - Pindahkan
rightdarilefthingga akhir list, lalu tambahkannums[right]ketotal. - Setelah setiap penambahan, simpan
totalkebestjika nilainya lebih besar. - Kembalikan
best.
def maxSubArray(nums):
best = nums[0]
for left in range(len(nums)):
total = 0
# Grow the subarray that starts at left by one element at a time
for right in range(left, len(nums)):
total += nums[right]
best = max(best, total)
return bestAlgoritma Kadane
Intuisi
Rangkaian terbaik yang berakhir pada indeks i adalah nums[i] saja, atau rangkaian terbaik yang berakhir pada i-1 dengan menambahkan nums[i], karena tidak ada rangkaian lain yang berakhir pada i-1 dengan jumlah yang lebih besar. Jadi, simpan satu angka, endingHere, yaitu jumlah terbaik dari rangkaian yang berakhir pada elemen saat ini. Pada elemen berikutnya, x, nilainya menjadi yang lebih besar antara x dan endingHere + x: selama jumlah rangkaian positif, kamu memperpanjangnya, dan begitu jumlahnya nol atau negatif, kamu memulai lagi dari x.
Subarray terbaik berakhir di suatu tempat, jadi jawabannya adalah nilai terbesar yang dicapai endingHere. Pada contoh pertama, nilainya berturut-turut adalah 2, -2, 3, 2, 7, 1, 2, dan jawabannya adalah 7.
Algoritma
- Atur
endingHeredanbestke elemen pertama. - Untuk setiap elemen berikutnya
x, aturendingHereke nilai yang lebih besar antaraxdanendingHere + x. - Atur
bestke nilai yang lebih besar antarabestdanendingHere. - Setelah elemen terakhir, kembalikan
best.
def maxSubArray(nums):
current = nums[0]
best = nums[0]
for i in range(1, len(nums)):
current = max(nums[i], current + nums[i])
best = max(best, current)
return best
Jebakan dan kasus tepi
- Memulai
bestdari 0.[-3, -1, -2]kemudian menghasilkan 0, bukan -1. Mulailah dari elemen pertama. - Membatasi jumlah sementara dengan
max(0, endingHere + x). Cara ini gagal pada list yang sama; bandingkan denganx. - Menjumlahkan hanya angka positif. Elemen-elemen tersebut harus bersebelahan, jadi contoh pertama menghasilkan 7, bukan 2 + 3 + 5 + 1 = 11.
- Memulai perulangan pada indeks 1 tanpa menetapkan
endingHeredanbestkenums[0]. List yang hanya memiliki satu elemen, seperti[-5], harus menghasilkan -5.
Pertanyaan yang sering diajukan3
Apa itu algoritma Kadane?
Algoritma Kadane menemukan jumlah terbesar dari subarray berurutan dalam satu kali lintasan. Algoritma ini menyimpan jumlah terbaik dari rangkaian yang berakhir pada elemen saat ini dan, pada setiap elemen baru, memilih untuk melanjutkan rangkaian tersebut atau memulai rangkaian baru. Jumlah terbesar dari nilai-nilai ini adalah jawabannya.
Berapa kompleksitas waktu dari Maximum Subarray?
Algoritma Kadane membutuhkan waktu O(n) dan ruang tambahan O(1), karena setiap elemen diperiksa satu kali. Memeriksa setiap subarray dengan total berjalan membutuhkan O(n²), sedangkan menjumlahkan setiap subarray dari awal membutuhkan O(n³).
Mengapa Maximum Subarray merupakan masalah pemrograman dinamis?
Jumlah terbaik dari perulangan yang berakhir pada indeks i hanya bergantung pada jumlah terbaik dari perulangan yang berakhir pada i-1. Ini adalah relasi rekurensi atas indeks, ciri khas pemrograman dinamis. Algoritma Kadane hanya menyimpan nilai terbaru, bukan seluruh tabel, sehingga hanya membutuhkan ruang O(1).
Soal serupa
Soal yang memakai ide yang sama. Mengerjakan dua atau tiga di antaranya membuat polanya melekat.
def maxSubArray(nums):
# Tulis kodemu di siniTes #1
Tes #2
Argumen
nums = [2, -4, 3, -1, 5, -6, 1]
Output yang diharapkan
7