Move Zeroes
Kamu mendapatkan array bilangan bulat nums. Pindahkan setiap 0 ke akhir array dan pertahankan urutan nilai lainnya. Kembalikan array yang telah disusun ulang, dengan panjang yang sama seperti nums.
Fungsi
- numsinteger-array
- array bilangan bulat yang akan disusun ulang
- Mengembalikaninteger-array
- nums dengan nilai bukan nol di awal, dalam urutan aslinya, dan setiap 0 di akhir
Batasan
1 ≤ nums.length ≤ 5000-105 ≤ nums[i] ≤ 105
Contoh
- Input
- nums = [0, 4, 0, 7, 2]
- Output
- [4, 7, 2, 0, 0]
- Penjelasan
- Nilai yang bukan 0 adalah 4, 7, dan 2, dan urutannya tetap sama di bagian depan. Dua angka 0 mengisi dua tempat terakhir.
- Input
- nums = [-3, 8, 1]
- Output
- [-3, 8, 1]
- Penjelasan
- Tidak ada 0 yang perlu dipindahkan, jadi array tetap sama. -3 bernilai negatif, bukan nol, jadi tetap berada di posisi pertama.
- Input
- nums = [0]
- Output
- [0]
- Penjelasan
- array yang berisi satu 0 sudah memiliki bentuk akhir.
Pertanyaan lanjutan
Bisakah kamu memindahkan setiap 0 ke depan, dengan tetap mempertahankan urutan nilai lainnya, dalam satu kali lintasan dengan memori tambahan O(1)?
Petunjuk
Buka satu per satu. Setiap petunjuk mengungkap sedikit lebih banyak.
Bayangkan array yang sudah selesai: nilai bukan nol dalam urutan lama, lalu angka nol. Di mana nilai bukan nol pertama yang kamu temui harus berada?
Pertahankan indeks
writeuntuk posisi kosong berikutnya di bagian depan. Setiap nilai bukan nol yang kamu temui harus ditempatkan tepat di sana, lalu posisinya bergeser satu langkah ke kanan.Telusuri dengan indeks kedua
read. Saatnums[read]bukan 0, tukar dengannums[write]lalu geserwriteke depan. Semua yang berada di antara kedua indeks selalu 0, jadi setiap pertukaran mendorong 0 ke belakang dan menjaga nilai lainnya tetap berurutan.
Solusi
Kendalanya adalah menjaga nilai lainnya tetap dalam urutan semula, sehingga menukar setiap 0 dengan elemen terakhir bukanlah pilihan. Satu indeks membaca setiap elemen, indeks kedua menandai posisi nilai bukan nol berikutnya, dan satu kali lintasan menyelesaikan tugas ini di tempat.
Salin nilai yang bukan nol
Intuisi
Salin setiap nilai bukan nol ke dalam array baru sesuai urutan kamu menemukannya, lalu tambahkan nol hingga panjangnya sama dengan nums. Urutannya tetap benar karena kamu menyalin nilai sesuai urutan kamu membacanya.
Setiap elemen dibaca sekali dan ditulis sekali: waktu O(n), ditambah memori O(n) untuk array kedua.
Algoritma
- Buat array hasil yang kosong.
- Untuk setiap nilai dalam
nums, tambahkan ke hasil jika nilainya bukan 0. - Tambahkan nol hingga hasil memiliki jumlah entri yang sama dengan
nums. - Kembalikan hasil.
def moveZeroes(nums):
result = [x for x in nums if x != 0]
result += [0] * (len(nums) - len(result))
return resultDua pointer, menukar secara langsung
Intuisi
Setelah setiap langkah, berlaku dua fakta: semua yang berada sebelum write adalah nilai bukan nol yang telah terlihat sejauh ini, sesuai urutan, dan semua yang berada dari write hingga read adalah 0. Jika nums[read] bukan nol, nilainya bertukar dengan nums[write], sehingga nilai yang berada di read menjadi 0, atau tetap sama jika kedua indeks tersebut sama. Nilai bukan nol hanya melompati 0, tidak pernah saling melompati, sehingga urutannya tetap terjaga.
Pada [0, 4, 0, 7, 2], nilai 4, 7, dan 2 bertukar ke indeks 0, 1, dan 2 secara berurutan, lalu nilai 0 berakhir di indeks 3 dan 4. Satu kali lintasan tanpa array kedua: waktu O(n) dan memori O(1).
Algoritma
- Atur
writeke 0. - Pindahkan
readdari indeks pertama ke indeks terakhir. - Jika
nums[read]bukan 0, tukarnums[read]dengannums[write], lalu tambahkan 1 kewrite. - Kembalikan
nums.
def moveZeroes(nums):
write = 0 # nums[:write] holds the non-zero values found so far, in order
for read in range(len(nums)):
if nums[read] != 0:
nums[write], nums[read] = nums[read], nums[write]
write += 1
return nums
Jebakan dan kasus tepi
- Menukar setiap 0 dengan elemen terakhir. Itu memindahkan angka nol, tetapi mengacak elemen lainnya:
[0, 4, 7]menjadi[7, 4, 0]. - Menghapus angka nol saat indeks bergerak menelusuri array. Dalam
[0, 0, 5], menghapus indeks 0 menggeser angka 0 kedua ke indeks 0, sementara perulangan berlanjut ke indeks 1. Setiap penghapusan juga menggeser sisa array, sehingga perulangannya memiliki kompleksitasO(n²). - Menguji
x > 0, bukanx != 0. Nilai negatif bukan angka nol:[-1, 0, -2]harus menjadi[-1, -2, 0], tetapi versi yang menyalin array akan menghasilkan[0, 0, 0].
Pertanyaan yang sering diajukan3
Berapa kompleksitas waktu Move Zeroes?
O(n): kedua pendekatan membaca setiap elemen satu kali. Menyalin nilai bukan nol ke dalam array baru membutuhkan memori tambahan O(n), sedangkan pertukaran dengan dua pointer bekerja di dalam array dengan memori tambahan O(1).
Apakah Pindahkan Angka Nol bisa dilakukan dengan lebih sedikit penulisan?
Ya. Alih-alih menukar, salin setiap nilai bukan nol ke nums[write], lalu setelah pemindaian, isi setiap posisi dari write hingga akhir dengan 0. Dengan begitu, setiap posisi ditulis paling banyak satu kali. Kamu juga bisa melewati penukaran jika read sama dengan write, karena nilainya akan dikembalikan ke tempat yang sama.
Mengapa Move Zeroes merupakan masalah dua pointer?
Satu pointer membaca setiap elemen dan pointer lainnya menandai akhir bagian depan yang sudah selesai. Keduanya hanya bergerak maju, sehingga bersama-sama melakukan satu kali lintasan. Pola baca dan tulis yang sama menghapus duplikat dari array yang sudah diurutkan atau memfilter nilai apa pun dari array secara langsung.
Soal serupa
Soal yang memakai ide yang sama. Mengerjakan dua atau tiga di antaranya membuat polanya melekat.
def moveZeroes(nums):
# Tulis kodemu di siniTes #1
Tes #2
Tes #3
Argumen
nums = [0, 4, 0, 7, 2]
Output yang diharapkan
[4, 7, 2, 0, 0]