Saya telah diberikan pertanyaan wawancara ini:
Diberikan file input dengan empat miliar bilangan bulat, berikan algoritma untuk menghasilkan bilangan bulat yang tidak terkandung dalam file. Asumsikan Anda memiliki memori 1 GB. Tindak lanjuti apa yang akan Anda lakukan jika Anda hanya memiliki 10 MB memori.
Analisis saya:
Ukuran file adalah 4 × 10 9 × 4 byte = 16 GB.
Kita dapat melakukan penyortiran eksternal, sehingga memberi tahu kita kisaran bilangan bulat.
Pertanyaan saya adalah apa cara terbaik untuk mendeteksi bilangan bulat yang hilang dalam rangkaian bilangan bulat besar yang diurutkan?
Pemahaman saya (setelah membaca semua jawaban):
Dengan asumsi kita berbicara tentang bilangan bulat 32-bit, ada 2 32 = 4 * 10 9 bilangan bulat yang berbeda.
Kasus 1: kami memiliki 1 GB = 1 * 10 9 * 8 bit = 8 miliar bit memori.
Larutan:
Jika kita menggunakan satu bit yang mewakili satu integer yang berbeda, itu sudah cukup. kita tidak perlu menyortir.
Penerapan:
int radix = 8;
byte[] bitfield = new byte[0xffffffff/radix];
void F() throws FileNotFoundException{
Scanner in = new Scanner(new FileReader("a.txt"));
while(in.hasNextInt()){
int n = in.nextInt();
bitfield[n/radix] |= (1 << (n%radix));
}
for(int i = 0; i< bitfield.lenght; i++){
for(int j =0; j<radix; j++){
if( (bitfield[i] & (1<<j)) == 0) System.out.print(i*radix+j);
}
}
}
Kasus 2: 10 MB memori = 10 * 10 6 * 8 bit = 80 juta bit
Larutan:
Untuk semua kemungkinan awalan 16-bit, ada 2 16 jumlah bilangan bulat = 65536, kita membutuhkan 2 16 * 4 * 8 = 2 juta bit. Kita perlu membangun 65536 ember. Untuk setiap bucket, kita membutuhkan 4 byte yang menyimpan semua kemungkinan karena kasus terburuk adalah semua 4 miliar bilangan bulat milik bucket yang sama.
- Buat konter setiap bucket melalui pass pertama melalui file.
- Pindai ember, temukan yang pertama yang memiliki kurang dari 65536 hit.
- Bangun bucket baru dengan awalan 16-bit yang tinggi, kami temukan di langkah 2 hingga pass kedua file
- Pindai ember yang ada di langkah 3, temukan ember pertama yang tidak memiliki hit.
Kode ini sangat mirip dengan yang di atas.
Kesimpulan: Kami mengurangi memori melalui peningkatan pass file.
Klarifikasi untuk mereka yang datang terlambat: Pertanyaan, seperti yang ditanyakan, tidak mengatakan bahwa ada tepat satu bilangan bulat yang tidak terdapat dalam file — setidaknya itu bukan cara kebanyakan orang mengartikannya. Banyak komentar di thread komentar yang tentang itu variasi tugas, meskipun. Sayangnya komentar yang memperkenalkannya ke utas komentar kemudian dihapus oleh penulisnya, jadi sekarang sepertinya balasan yatim untuk itu hanya salah mengerti segalanya. Sangat membingungkan, maaf.
sumber
int getMissingNumber(File inputFile) { return 4; }
( referensi )Jawaban:
Dengan asumsi bahwa "integer" berarti 32 bit : 10 MB ruang lebih dari cukup bagi Anda untuk menghitung berapa banyak angka yang ada dalam file input dengan awalan 16-bit yang diberikan, untuk semua awalan 16-bit yang mungkin dalam satu melewati masukan file. Setidaknya satu dari ember akan terkena kurang dari 2 16 kali. Lakukan operan kedua untuk menemukan nomor mana yang mungkin dalam ember yang sudah digunakan.
Jika itu berarti lebih dari 32 bit, tetapi masih berukuran terbatas : Lakukan seperti di atas, abaikan semua nomor input yang berada di luar kisaran 32-bit (yang ditandatangani atau tidak ditandatangani; pilihan Anda).
Jika "integer" berarti integer matematis : Baca input sekali dan pantau panjang
bilangan terbesardari bilangan terpanjang yang pernah Anda lihat. Setelah selesai, hasilkanmaksimum ditambah satuangka acak yang memiliki satu digit lagi. (Salah satu angka dalam file mungkin bignum yang membutuhkan lebih dari 10 MB untuk mewakili secara tepat, tetapi jika inputnya adalah file, maka Anda setidaknya dapat mewakili panjang apa pun yang cocok di dalamnya).sumber
Algoritma yang diinformasikan secara statistik memecahkan masalah ini menggunakan lebih sedikit operan daripada pendekatan deterministik.
Jika bilangan bulat yang sangat besar diizinkan maka seseorang dapat menghasilkan angka yang cenderung unik dalam waktu O (1). Bilangan bulat 128-bit pseudo-acak seperti GUID hanya akan bertabrakan dengan salah satu dari empat miliar bilangan bulat dalam set dalam waktu kurang dari satu dari setiap 64 miliar miliar miliar kasus.
Jika bilangan bulat dibatasi hingga 32 bit, maka seseorang dapat menghasilkan angka yang cenderung unik dalam satu kali lintasan menggunakan jauh lebih sedikit dari 10 MB. Kemungkinan bahwa integer 32-bit semu akan bertabrakan dengan salah satu dari 4 miliar bilangan bulat yang ada adalah sekitar 93% (4e9 / 2 ^ 32). Peluang bahwa 1000 bilangan bulat pseudo-acak semua akan bertabrakan kurang dari satu dalam 12.000 miliar miliar miliar (odds-of-one-collision ^ 1000). Jadi, jika suatu program mempertahankan struktur data yang berisi 1000 kandidat pseudo-acak dan iterasi melalui bilangan bulat yang diketahui, menghilangkan kecocokan dari para kandidat, semuanya pasti akan menemukan setidaknya satu bilangan bulat yang tidak ada dalam file.
sumber
Diskusi terperinci tentang masalah ini telah dibahas dalam Jon Bentley "Kolom 1. Pemecahan Kerang" Programming Pearls Addison-Wesley hal.3-10
Bentley membahas beberapa pendekatan, termasuk pengurutan eksternal, Gabung Sortir menggunakan beberapa file eksternal, dll., Namun metode terbaik yang disarankan Bentley adalah algoritma lintasan tunggal menggunakan bidang bit , yang dengan lucu ia sebut "Wonder Sort" :) Datang ke masalah, 4 miliar angka dapat direpresentasikan dalam:
Kode untuk mengimplementasikan bitset itu sederhana: (diambil dari halaman solusi )
Algoritma Bentley membuat satu melewati file,
set
ting bit yang sesuai dalam array dan kemudian memeriksa array ini menggunakantest
makro di atas untuk menemukan nomor yang hilang.Jika memori yang tersedia kurang dari 0,466 GB, Bentley menyarankan algoritma k-pass, yang membagi input menjadi rentang tergantung pada memori yang tersedia. Untuk mengambil contoh yang sangat sederhana, jika hanya 1 byte (yaitu memori untuk menangani 8 angka) tersedia dan rentangnya dari 0 hingga 31, kami membaginya dalam rentang 0 hingga 7, 8-15, 16-22 dan seterusnya. dan menangani kisaran ini di setiap
32/8 = 4
lintasan.HTH.
sumber
!= -1
masih akan menjenuhkan bandwidth memori yang berjalan pada satu inti (ini adalah SIMD-dalam-register, SWAR, dengan bit sebagai elemen). (Untuk desain Intel / AMD terbaru). Anda hanya perlu mencari tahu bit mana yang tidak disetel setelah Anda menemukan lokasi 64bit yang mengandungnya. (Dan untuk itu Anda bisanot / lzcnt
.) Poin wajar yang mengulang tes satu-bit mungkin tidak dioptimalkan dengan baik.Karena masalahnya tidak menentukan bahwa kita harus menemukan angka sekecil mungkin yang tidak ada dalam file kita hanya bisa menghasilkan angka yang lebih panjang daripada file input itu sendiri. :)
sumber
int
adalah32
bit, hanya output2^64-1
. Selesaitr -d '\n' < nums.txt > new_num.txt
:: DUntuk varian RAM 1 GB Anda dapat menggunakan vektor sedikit. Anda perlu mengalokasikan 4 milyar bit == 500 MB byte byte. Untuk setiap angka yang Anda baca dari input, atur bit yang sesuai ke '1'. Setelah selesai, ulangi bit-bitnya, temukan bit pertama yang masih '0'. Indeksnya adalah jawabannya.
sumber
bitSet.nextClearBit(0)
: download.oracle.com/javase/6/docs/api/java/util/…Jika mereka adalah bilangan bulat 32-bit (kemungkinan dari pilihan ~ 4 miliar angka mendekati 2 32 ), daftar 4 miliar angka Anda akan menggunakan paling banyak 93% dari bilangan bulat yang mungkin (4 * 10 9 / (2 32 ) ). Jadi jika Anda membuat bit-array 2 32 bit dengan masing-masing bit diinisialisasi ke nol (yang akan memakan waktu 2 29 byte ~ 500 MB RAM; ingat satu byte = 2 3 bit = 8 bit), bacalah daftar integer Anda dan untuk setiap int atur elemen bit-array yang sesuai dari 0 hingga 1; dan kemudian baca seluruh bit-array Anda dan kembalikan bit pertama yang masih 0.
Jika RAM Anda lebih sedikit (~ 10 MB), solusi ini perlu sedikit dimodifikasi. 10 MB ~ 83886080 bit masih cukup untuk melakukan bit-array untuk semua angka antara 0 dan 83886079. Jadi, Anda dapat membaca daftar int; dan hanya catat #s yang berada di antara 0 dan 83886079 dalam larik bit Anda. Jika jumlahnya didistribusikan secara acak; dengan probabilitas luar biasa (berbeda 100% sekitar 10 -2592069 ), Anda akan menemukan int yang hilang). Bahkan, jika Anda hanya memilih angka 1 hingga 2048 (dengan hanya 256 byte RAM), Anda masih akan menemukan angka yang hilang dengan persentase yang luar biasa (99,9999999999999999999999999999999999999999999999999999999999999999999995%) saat itu.
Tetapi katakanlah alih-alih memiliki sekitar 4 miliar angka; Anda memiliki sekitar 2 32 - 1 angka dan kurang dari 10 MB RAM; jadi setiap rentang int yang kecil hanya memiliki kemungkinan kecil untuk tidak mengandung nomor tersebut.
Jika Anda dijamin bahwa setiap int dalam daftar itu unik, Anda dapat menjumlahkan angka dan mengurangi jumlah dengan satu # hilang dengan jumlah penuh (½) (2 32 ) (2 32 - 1) = 9223372034707292160 untuk menemukan int yang hilang . Namun, jika sebuah int terjadi dua kali, metode ini akan gagal.
Namun, Anda selalu dapat membagi dan menaklukkan. Metode naif, akan membaca array dan menghitung jumlah angka yang ada di babak pertama (0 hingga 2 31 -1) dan babak kedua (2 31 , 2 32 ). Kemudian pilih rentang dengan angka yang lebih sedikit dan ulangi membagi rentang itu menjadi dua. (Katakan jika ada dua angka kurang dalam (2 31 , 2 32 ) maka pencarian Anda berikutnya akan menghitung angka dalam kisaran (2 31 , 3 * 2 30 -1), (3 * 2 30 , 2 32 ). ulangi sampai Anda menemukan rentang dengan angka nol dan Anda memiliki jawaban Anda. Harus mengambil O (lg N) ~ 32 membaca melalui array.
Metode itu tidak efisien. Kami hanya menggunakan dua bilangan bulat di setiap langkah (atau sekitar 8 byte RAM dengan bilangan bulat 4 byte (32-bit)). Metode yang lebih baik adalah dengan membagi menjadi sqrt (2 32 ) = 2 16 = 65536 nampan, masing-masing dengan 65536 angka dalam bin. Setiap bin membutuhkan 4 byte untuk menyimpan hitungannya, jadi Anda perlu 2 18 byte = 256 kB. Jadi bin 0 adalah (0 hingga 65535 = 2 16 -1), bin 1 adalah (2 16 = 65536 hingga 2 * 2 16 -1 = 131071), bin 2 adalah (2 * 2 16 = 131072 hingga 3 * 2 16 - 1 = 196607). Dengan python Anda akan memiliki sesuatu seperti:
Bacalah daftar integer ~ 4 miliar; dan hitung berapa banyak int yang jatuh di masing-masing 2 16 nampan dan temukan tidak lengkap_bin yang tidak memiliki semua 65536 angka. Kemudian Anda membaca daftar bilangan bulat 4 miliar lagi; tapi kali ini hanya perhatikan ketika bilangan bulat berada dalam kisaran itu; membalik sedikit ketika Anda menemukannya.
sumber
Mengapa membuatnya begitu rumit? Anda meminta bilangan bulat yang tidak ada dalam file?
Menurut aturan yang ditentukan, satu-satunya hal yang Anda butuhkan untuk menyimpan adalah bilangan bulat terbesar yang Anda temui sejauh ini dalam file. Setelah seluruh file dibaca, kembalikan angka 1 lebih besar dari itu.
Tidak ada risiko memukul maxint atau apa pun, karena menurut aturan, tidak ada batasan untuk ukuran bilangan bulat atau jumlah yang dikembalikan oleh algoritma.
sumber
Ini dapat diselesaikan dalam ruang yang sangat sedikit menggunakan varian pencarian biner.
Mulai dengan rentang angka yang diizinkan,
0
hingga4294967295
.Hitung titik tengahnya.
Loop melalui file, menghitung berapa angka yang sama, kurang dari atau lebih tinggi dari nilai titik tengah.
Jika tidak ada angka yang sama, Anda selesai. Nomor titik tengah adalah jawabannya.
Jika tidak, pilih rentang yang memiliki angka paling sedikit dan ulangi dari langkah 2 dengan rentang baru ini.
Ini akan membutuhkan hingga 32 pemindaian linear melalui file, tetapi hanya akan menggunakan beberapa byte memori untuk menyimpan rentang dan jumlah.
Ini pada dasarnya sama dengan solusi Henning , kecuali menggunakan dua tempat sampah bukannya 16k.
sumber
EDIT Ok, ini tidak cukup dipikirkan karena mengasumsikan bilangan bulat dalam file mengikuti beberapa distribusi statis. Tampaknya mereka tidak perlu melakukannya, tetapi meskipun demikian orang harus mencoba ini:
Ada .34,3 miliar bilangan bulat 32-bit. Kami tidak tahu bagaimana mereka didistribusikan dalam file, tetapi kasus terburuk adalah yang dengan entropi Shannon tertinggi: distribusi yang sama. Dalam hal ini, kemungkinan salah satu integer tidak muncul dalam file adalah
((2³²-1) / 2³²) ⁴ ⁰⁰⁰ ⁰⁰⁰ ⁰⁰⁰ ≈ .4
Semakin rendah entropi Shannon, semakin tinggi probabilitas ini pada rata-rata, tetapi bahkan untuk kasus terburuk ini kami memiliki peluang 90% untuk menemukan nomor yang tidak berulang setelah 5 tebakan dengan bilangan bulat acak. Cukup buat angka seperti itu dengan generator pseudorandom, simpan dalam daftar. Kemudian baca int setelah int dan bandingkan dengan semua tebakan Anda. Ketika ada kecocokan, hapus entri daftar ini. Setelah melalui semua file, kemungkinan Anda akan memiliki lebih dari satu tebakan tersisa. Gunakan salah satunya. Dalam peristiwa langka (10% bahkan pada kasus terburuk) tanpa tebakan tersisa, dapatkan satu set bilangan bulat acak baru, mungkin lebih banyak kali ini (10-> 99%).
Konsumsi memori: beberapa lusin byte, kompleksitas: O (n), overhead: neclectable karena sebagian besar waktu akan dihabiskan dalam mengakses hard disk yang tidak dapat dihindari daripada membandingkan ints pula.
Kasus terburuk sebenarnya, ketika kita tidak menganggap distribusi statis, adalah bahwa setiap bilangan bulat terjadi maks. sekali, karena dengan demikian hanya 1 - 4000000000 / 2³² ≈ 6% dari semua bilangan bulat tidak muncul dalam file. Jadi Anda akan membutuhkan beberapa tebakan lagi, tetapi itu masih tidak membutuhkan biaya memori yang menyakitkan.
sumber
Jika Anda memiliki satu bilangan bulat yang hilang dari rentang [0, 2 ^ x - 1] maka cukup kombinasikan semuanya. Sebagai contoh:
(Saya tahu ini tidak menjawab pertanyaan dengan tepat , tetapi ini adalah jawaban yang bagus untuk pertanyaan yang sangat mirip.)
sumber
0 ^ 1 ^ 3 ^ 4 ^ 6 ^ 7
adalah 0. [ Menulis 2 x untuk 2 hingga kekuatan ke X'th, dan a ^ b untuk xor b, xor dari semua k <2 x adalah nol - k ^ ~ k = (2 ^ x) - 1 untuk k <2 ^ (x-1), dan k ^ ~ k ^ j ^ ~ j = 0 ketika j = k + 2 ** (x-2) - jadi xor dari semua kecuali satu angka adalah nilainya dari yang hilang]Mereka mungkin mencari untuk melihat apakah Anda pernah mendengar tentang Bloom Filter probabilistik yang dapat sangat efisien menentukan secara absolut jika suatu nilai bukan bagian dari set besar, (tetapi hanya dapat menentukan dengan probabilitas tinggi itu adalah anggota set tersebut.)
sumber
Berdasarkan kata-kata saat ini dalam pertanyaan awal, solusi paling sederhana adalah:
Temukan nilai maksimum dalam file, lalu tambahkan 1 ke dalamnya.
sumber
Gunakan a
BitSet
. 4 miliar bilangan bulat (dengan asumsi hingga 2 ^ 32 bilangan bulat) yang dikemas ke dalam BitSet pada 8 per byte adalah 2 ^ 32/2 ^ 3 = 2 ^ 29 = sekitar 0,5 Gb.Untuk menambahkan sedikit lebih detail - setiap kali Anda membaca angka, atur bit yang sesuai di BitSet. Kemudian, lakukan lewati BitSet untuk menemukan nomor pertama yang tidak ada. Bahkan, Anda bisa melakukan ini sama efektifnya dengan berulang kali memilih nomor acak dan menguji jika ada.
Sebenarnya BitSet.nextClearBit (0) akan memberi tahu Anda bit pertama yang tidak disetel.
Melihat pada BitSet API, tampaknya hanya mendukung 0..MAX_INT, jadi Anda mungkin memerlukan 2 BitSets - satu untuk nomor + ve dan satu untuk-sudah nomor - tetapi persyaratan memori tidak berubah.
sumber
BitSet
... coba array bit. Apakah hal yang sama;)Jika tidak ada batasan ukuran, cara tercepat adalah mengambil panjang file, dan menghasilkan panjang file + 1 angka acak (atau hanya "11111 ..."). Keuntungan: Anda bahkan tidak perlu membaca file, dan Anda dapat meminimalkan penggunaan memori hampir nol. Kekurangan: Anda akan mencetak miliaran digit.
Namun, jika satu-satunya faktor adalah meminimalkan penggunaan memori, dan tidak ada yang penting, ini akan menjadi solusi optimal. Bahkan mungkin memberi Anda penghargaan "penyalahgunaan terburuk aturan".
sumber
Jika kita mengasumsikan bahwa rentang angka akan selalu 2 ^ n (kekuatan genap 2), maka eksklusif-atau akan berfungsi (seperti yang ditunjukkan oleh poster lain). Sejauh mengapa, mari kita buktikan:
Teori
Dengan rentang integer berbasis 0 yang memiliki
2^n
elemen dengan satu elemen hilang, Anda dapat menemukan elemen yang hilang hanya dengan xor-ing nilai yang diketahui bersama-sama untuk menghasilkan angka yang hilang.Bukti
Mari kita lihat n = 2. Untuk n = 2, kita dapat mewakili 4 bilangan bulat unik: 0, 1, 2, 3. Mereka memiliki pola bit:
Sekarang, jika kita perhatikan, masing-masing dan setiap bit diatur tepat dua kali. Oleh karena itu, karena ditetapkan beberapa kali, dan eksklusif-atau dari angka akan menghasilkan 0. Jika satu angka hilang, eksklusif-atau akan menghasilkan angka bahwa ketika eksklusif-ored dengan angka yang hilang akan menghasilkan 0. Oleh karena itu, nomor yang hilang, dan nomor eksklusif yang dihasilkan sama persis. Jika kita menghapus 2, xor yang dihasilkan akan
10
(atau 2).Sekarang, mari kita lihat n +1. Mari kita panggil berapa kali setiap bit diatur
n
,x
dan berapa kali setiap bit diaturn+1
y
. Nilaiy
akan sama dengany = x * 2
karena adax
elemen dengann+1
bit yang diatur ke 0, danx
elemen dengann+1
bit yang diatur ke 1. Dan karena2x
akan selalu genap,n+1
akan selalu ada setiap bit yang menetapkan angka genap berapa kali.Oleh karena itu, sejak
n=2
berfungsi, dann+1
berfungsi, metode xor akan bekerja untuk semua nilain>=2
.Algoritma Untuk Rentang Berbasis 0
Ini cukup sederhana. Ia menggunakan 2 * n bit memori, jadi untuk rentang apa pun <= 32, 2 bilangan bulat 32 akan bekerja (mengabaikan semua memori yang dikonsumsi oleh deskriptor file). Dan itu membuat satu pass file.
Algoritma Untuk Ranges Berbasis Sewenang-wenang
Algoritma ini akan bekerja untuk rentang dari setiap angka awal ke angka akhir mana pun, asalkan total rentangnya sama dengan 2 ^ n ... Ini pada dasarnya mendasarkan kembali rentang untuk memiliki minimum pada 0. Tetapi diperlukan 2 lintasan melalui file (yang pertama untuk meraih minimum, yang kedua untuk menghitung int yang hilang).
Ranges sewenang-wenang
Kita dapat menerapkan metode yang dimodifikasi ini untuk satu set rentang arbitrer, karena semua rentang akan melintasi kekuatan 2 ^ n setidaknya sekali. Ini hanya berfungsi jika ada satu bit yang hilang. Dibutuhkan 2 pass dari file yang tidak disortir, tetapi akan menemukan nomor yang hilang setiap kali:
Pada dasarnya, basiskan kembali rentang sekitar 0. Kemudian, ia menghitung jumlah nilai yang tidak disortir untuk ditambahkan saat menghitung eksklusif-atau. Kemudian, ia menambahkan 1 ke hitungan nilai yang tidak disortir untuk menjaga nilai yang hilang (hitung yang hilang). Kemudian, pertahankan xoring nilai n, bertambah 1 setiap kali hingga n adalah kekuatan 2. Hasilnya kemudian kembali berdasarkan basis asli. Selesai
Berikut algoritma yang saya uji dalam PHP (menggunakan array bukan file, tetapi konsep yang sama):
Diberikan dalam array dengan rentang nilai apa pun (saya uji termasuk negatif) dengan satu di dalam rentang yang hilang, itu menemukan nilai yang benar setiap kali.
Pendekatan Lain
Karena kita dapat menggunakan penyortiran eksternal, mengapa tidak memeriksa celahnya saja? Jika kami menganggap file diurutkan sebelum menjalankan algoritma ini:
sumber
sum(0..n) = n*(n+1)/2
. Jadimissing = nmax*(nmax+1)/2 - nmin*(nmin+1)/2 - sum(input[])
. (jumlah ide dari jawaban @ hammar.)Tipuan pertanyaan, kecuali jika dikutip dengan tidak tepat. Cukup baca file sekali untuk mendapatkan integer maksimum
n
, dan kembalin+1
.Tentu saja Anda akan memerlukan rencana cadangan jika seandainya
n+1
menyebabkan integer overflow.sumber
Periksa ukuran file input, output maka setiap jumlah yang terlalu besar untuk diwakili oleh sebuah file yang ukuran. Ini mungkin tampak seperti trik murah, tetapi ini adalah solusi kreatif untuk masalah wawancara, itu dengan rapi menghindari masalah memori, dan secara teknis O (n).
Harus mencetak 10 bitcount - 1 , yang akan selalu lebih besar dari 2 bitcount . Secara teknis, angka yang harus Anda kalahkan adalah 2 bitcount - (4 * 10 9 - 1) , karena Anda tahu ada (4 miliar - 1) bilangan bulat lain dalam file, dan bahkan dengan kompresi sempurna mereka akan mengambil setidaknya masing-masing sedikit.
sumber
Console.Write( 1 << bitcount )
sebagai ganti loop? Jika ada n bit dalam file, maka nomor bit + 1 apa pun dengan angka 1 terkemuka mutlak dijamin lebih besar.<<
operator. Either way, kecuali Anda menggulung tipe integer raksasa Anda sendiri, itu akan menjadi ukuran file yang sangat kecil. Demo: rextester.com/BLETJ59067Pendekatan paling sederhana adalah menemukan angka minimum dalam file, dan mengembalikan 1 kurang dari itu. Ini menggunakan O (1) penyimpanan, dan O (n) waktu untuk file n angka. Namun, itu akan gagal jika rentang angka terbatas, yang bisa membuat min-1 bukan-angka.
Metode sederhana dan mudah menggunakan bitmap telah disebutkan. Metode itu menggunakan O (n) waktu dan penyimpanan.
Metode 2-pass dengan 2 ^ 16 menghitung-ember juga telah disebutkan. Bunyinya 2 * n integer, jadi gunakan O (n) waktu dan O (1) penyimpanan, tetapi tidak dapat menangani dataset dengan lebih dari 2 ^ 16 angka. Namun, itu mudah diperluas ke (misalnya) 2 ^ 60 bilangan bulat 64-bit dengan menjalankan 4 lintasan alih-alih 2, dan mudah disesuaikan dengan menggunakan memori kecil dengan menggunakan hanya banyak sampah yang sesuai dengan memori dan meningkatkan jumlah lintasan yang sesuai, di case run time tidak lagi O (n) tetapi sebaliknya O (n * log n).
Metode XOR'ing semua angka bersama, disebutkan sejauh ini oleh rfrankel dan panjangnya oleh ircmaxell menjawab pertanyaan yang diajukan dalam stackoverflow # 35185 , seperti yang ditunjukkan oleh ltn100. Ini menggunakan O (1) penyimpanan dan O (n) waktu berjalan. Jika untuk saat ini kita mengasumsikan bilangan bulat 32-bit, XOR memiliki probabilitas 7% untuk menghasilkan angka yang berbeda. Dasar Pemikiran: diberikan ~ angka-angka berbeda 4G XOR bersama, dan ca. 300M tidak dalam file, jumlah bit yang ditetapkan di setiap posisi bit memiliki peluang yang sama untuk menjadi ganjil atau genap. Dengan demikian, 2 ^ 32 angka memiliki kemungkinan yang sama muncul sebagai hasil XOR, di mana 93% sudah ada dalam file. Perhatikan bahwa jika angka-angka dalam file tidak semuanya berbeda, probabilitas keberhasilan metode XOR meningkat.
sumber
Untuk beberapa alasan, segera setelah saya membaca masalah ini saya memikirkan diagonalisasi. Saya mengasumsikan bilangan bulat besar sewenang-wenang.
Baca angka pertama. Kiri-pad dengan nol bit hingga Anda memiliki 4 miliar bit. Jika bit pertama (tingkat tinggi) adalah 0, output 1; selain itu output 0. (Anda tidak benar-benar harus meninggalkan-pad: Anda hanya output 1 jika tidak ada cukup bit dalam jumlahnya.) Lakukan hal yang sama dengan angka kedua, kecuali gunakan bit kedua. Lanjutkan melalui file dengan cara ini. Anda akan menghasilkan bit nomor 4 miliar satu bit pada satu waktu, dan angka itu tidak akan sama dengan yang ada di file. Bukti: itu sama dengan angka ke-n, maka mereka akan menyetujui bit ke-n, tetapi mereka tidak dengan konstruksi.
sumber
i
bit Anda hanya bisa menghasilkan 1 bit 4 miliar kali dan melemparkan 1 ekstra di akhir. Saya baik-baik saja dengan memiliki bilangan bulat besar dalam algoritma tetapi saya pikir masalahnya adalah untuk mengeluarkan bilangan bulat 32-bit yang hilang. Itu tidak masuk akal dengan cara lain.Anda bisa menggunakan tanda bit untuk menandai apakah integer ada atau tidak.
Setelah melintasi seluruh file, pindai setiap bit untuk menentukan apakah jumlahnya ada atau tidak.
Dengan asumsi masing-masing integer adalah 32 bit, mereka akan cocok dengan 1 GB RAM jika bit flagging dilakukan.
sumber
Dari Reddit oleh Carbonetc.
sumber
Hanya demi kelengkapan, berikut ini adalah solusi lain yang sangat sederhana, yang kemungkinan besar akan membutuhkan waktu yang sangat lama untuk dijalankan, tetapi menggunakan sedikit memori.
Biarkan semua integer yang memungkinkan menjadi rentang dari
int_min
hinggaint_max
, danbool isNotInFile(integer)
fungsi yang mengembalikan true jika file tidak mengandung integer tertentu dan false lainnya (dengan membandingkan integer tertentu itu dengan setiap integer dalam file)sumber
isNotInFile
fungsi. Pastikan Anda memahami pertanyaan sebelum menjawab.Untuk batasan memori 10 MB:
Setelah selesai, ambil jalur yang belum pernah dibuat sebelumnya untuk membuat nomor yang diminta.
4 miliar angka = 2 ^ 32, artinya 10 MB mungkin tidak cukup.
EDIT
Optimalisasi dimungkinkan, jika dua ujung daun telah dibuat dan memiliki induk yang sama, maka mereka dapat dihapus dan induk ditandai sebagai bukan solusi. Ini memotong cabang dan mengurangi kebutuhan akan memori.
EDIT II
Tidak perlu membangun pohon sepenuhnya juga. Anda hanya perlu membangun cabang yang dalam jika jumlahnya sama. Jika kita memotong cabang juga, maka solusi ini mungkin akan berhasil.
sumber
Saya akan menjawab versi 1 GB:
Tidak ada informasi yang cukup dalam pertanyaan, jadi saya akan menyatakan beberapa asumsi pertama:
Integer adalah 32 bit dengan kisaran -2,147.483.648 hingga 2.147.483.647.
Kode semu:
sumber
Selama kita melakukan jawaban kreatif, ini satu lagi.
Gunakan program pengurutan eksternal untuk mengurutkan file input secara numerik. Ini akan bekerja untuk sejumlah memori yang Anda miliki (ini akan menggunakan penyimpanan file jika diperlukan). Baca melalui file yang diurutkan dan output nomor pertama yang hilang.
sumber
Penghapusan bit
Salah satu caranya adalah dengan menghilangkan bit, namun ini mungkin tidak benar-benar menghasilkan hasil (kemungkinan tidak akan). Psuedocode:
Hitungan bit
Melacak jumlah bit; dan gunakan bit dengan jumlah paling sedikit untuk menghasilkan nilai. Sekali lagi ini tidak memiliki jaminan menghasilkan nilai yang benar.
Rentang Logika
Melacak rentang daftar yang dipesan (dipesan oleh awal). Rentang ditentukan oleh struktur:
Telusuri setiap nilai dalam file dan coba serta hapus dari rentang saat ini. Metode ini tidak memiliki jaminan memori, tetapi harus dilakukan dengan cukup baik.
sumber
2 128 * 10 18 +1 (yaitu (2 8 ) 16 * 10 18 +1) - tidak bisakah itu menjadi jawaban universal untuk hari ini? Ini merupakan angka yang tidak dapat disimpan dalam 16 file EB, yang merupakan ukuran file maksimum dalam sistem file saat ini.
sumber
Saya pikir ini adalah masalah yang diselesaikan (lihat di atas), tetapi ada kasus sampingan yang menarik untuk diingat karena mungkin ditanyakan:
Jika ada persis 4.294.967.295 (2 ^ 32 - 1) bilangan bulat 32-bit tanpa pengulangan, dan karena itu hanya satu yang hilang, ada solusi sederhana.
Mulai total berjalan di nol, dan untuk setiap integer dalam file, tambahkan integer itu dengan 32-bit overflow (efektif, runningTotal = (runningTotal + nextInteger)% 4294967296). Setelah selesai, tambahkan 4294967296/2 ke total yang berjalan, lagi dengan 32-bit overflow. Kurangi ini dari 4294967296, dan hasilnya adalah bilangan bulat yang hilang.
Masalah "hanya satu integer yang hilang" dapat dipecahkan dengan hanya satu kali dijalankan, dan hanya 64 bit RAM yang didedikasikan untuk data (32 untuk total yang berjalan, 32 untuk dibaca pada integer berikutnya).
Konsekuensi: Spesifikasi yang lebih umum sangat sederhana untuk dicocokkan jika kita tidak peduli dengan berapa banyak bit yang harus dimiliki oleh hasil integer. Kami hanya menghasilkan integer yang cukup besar sehingga tidak dapat dimuat dalam file yang kami berikan. Sekali lagi, ini membutuhkan RAM yang sangat minim. Lihat kodesemu.
sumber
Seperti kata Ryan pada dasarnya, urutkan file dan kemudian pergi ke bilangan bulat dan ketika nilai dilewati di sana Anda memilikinya :)
EDIT at downvoters: OP menyebutkan bahwa file dapat diurutkan jadi ini adalah metode yang valid.
sumber
Jika Anda tidak menganggap batasan 32-bit, kembalikan nomor 64-bit yang dihasilkan secara acak (atau 128-bit jika Anda pesimis). Peluang tabrakan adalah
1 in 2^64/(4*10^9) = 4611686018.4
(kira-kira 1 banding 4 milyar). Anda benar sebagian besar waktu!(Bercanda ... agak.)
sumber