Saya bingung tentang bagaimana vektor bit akan bekerja untuk melakukan ini (tidak terlalu terbiasa dengan vektor bit). Ini kode yang diberikan. Bisakah seseorang tolong menuntun saya melalui ini?
public static boolean isUniqueChars(String str) {
int checker = 0;
for (int i = 0; i < str.length(); ++i) {
int val = str.charAt(i) - 'a';
if ((checker & (1 << val)) > 0) return false;
checker |= (1 << val);
}
return true;
}
Terutama, apa yang checker
dilakukan?
java
string
bit-manipulation
bitvector
pengguna1136342
sumber
sumber
Jawaban:
int checker
digunakan di sini sebagai penyimpanan untuk bit. Setiap bit dalam nilai integer dapat diperlakukan sebagai flag, jadi akhirnyaint
adalah array bit (flag). Setiap bit dalam kode Anda menyatakan apakah karakter dengan indeks bit ditemukan dalam string atau tidak. Anda bisa menggunakan bit vektor untuk alasan yang sama, bukanint
. Ada dua perbedaan di antara mereka:Ukuran .
int
memiliki ukuran tetap, biasanya 4 byte yang berarti 8 * 4 = 32 bit (bendera). Vektor bit biasanya dapat berukuran berbeda atau Anda harus menentukan ukuran dalam konstruktor.API . Dengan vektor bit Anda akan lebih mudah membaca kode, mungkin kira-kira seperti ini:
vector.SetFlag(4, true); // set flag at index 4 as true
untuk
int
Anda akan memiliki kode logika bit level rendah:checker |= (1 << 5); // set flag at index 5 to true
Mungkin juga mungkin
int
sedikit lebih cepat, karena operasi dengan bit tingkat sangat rendah dan dapat dieksekusi apa adanya oleh CPU. BitVector memungkinkan penulisan kode cryptic sedikit lebih sedikit daripada itu dapat menyimpan lebih banyak flag.Untuk referensi di masa mendatang: bit vector juga dikenal sebagai bitSet atau bitArray. Berikut ini beberapa tautan ke struktur data ini untuk berbagai bahasa / platform:
sumber
Saya curiga Anda mendapatkan kode ini dari buku yang sama yang saya baca ... Kode itu sendiri di sini hampir tidak samar seperti operator- | =, &, dan << yang biasanya tidak digunakan oleh kami orang awam - penulis tidak repot-repot meluangkan waktu ekstra untuk menjelaskan prosesnya atau bagaimana sebenarnya mekanika yang terlibat di sini. Saya puas dengan jawaban sebelumnya pada utas ini di awal tetapi hanya pada tingkat abstrak. Saya kembali ke sana karena saya merasa perlu ada penjelasan yang lebih konkret - kurangnya orang selalu membuat saya merasa tidak enak.
Operator ini << adalah shifter bitwise kiri. Dibutuhkan representasi biner dari angka atau operan tersebut dan menggesernya ke atas, namun banyak tempat yang ditentukan oleh operan atau angka di sebelah kanan seperti dalam angka desimal hanya dalam biner. Kita mengalikan dengan basis 2 - ketika kita naik tetapi banyak tempat bukan basis 10 - jadi angka di sebelah kanan adalah eksponen dan angka di sebelah kiri adalah kelipatan basis dari 2.
Operator ini = mengambil operan di sebelah kiri dan atau itu dengan operan di kanan- dan ini - '&' dan bit dari kedua operan ke kiri dan kanan itu.
Jadi apa yang kita miliki di sini adalah tabel hash yang disimpan dalam angka biner 32 bit setiap kali pemeriksa mendapat (atau
checker |= (1 << val)
) dengan nilai biner yang ditunjuk dari sebuah huruf, bit terkaitnya disetel menjadi true. Nilai karakter adalah dan bersama checker (checker & (1 << val)) > 0
) - jika lebih besar dari 0 kita tahu kita memiliki dupe karena dua bit identik disetel ke true dan bersama-sama akan mengembalikan true atau '1' '.Ada 26 tempat biner yang masing-masing sesuai dengan huruf kecil-penulis mengatakan untuk menganggap string hanya berisi huruf kecil- dan ini karena kita hanya memiliki 6 lebih banyak (dalam bilangan bulat 32) tempat yang tersisa untuk dikonsumsi- dan daripada kita mendapatkan tabrakan
Jadi, untuk string input 'azya', saat kami bergerak langkah demi langkah
string 'a'
string 'az'
string 'azy'
string 'azya'
Sekarang, ini menyatakan duplikat
sumber
Saya pikir semua jawaban ini menjelaskan cara kerjanya, namun saya merasa ingin memberikan masukan tentang bagaimana saya melihatnya lebih baik, dengan mengganti nama beberapa variabel, menambahkan beberapa yang lain dan menambahkan komentar ke dalamnya:
sumber
Saya juga berasumsi bahwa contoh Anda berasal dari buku Cracking The Code Wawancara dan jawaban saya terkait dengan konteks ini.
Untuk menggunakan algoritma ini untuk menyelesaikan masalah, kita harus mengakui bahwa kita hanya akan meneruskan karakter dari a ke z (huruf kecil).
Karena hanya ada 26 huruf dan ini diurutkan dengan benar dalam tabel pengkodean yang kami gunakan, ini menjamin kami bahwa semua perbedaan potensial
str.charAt(i) - 'a'
akan lebih rendah dari 32 (ukuran variabel intchecker
).Seperti yang dijelaskan oleh Snowbear, kita akan menggunakan
checker
variabel sebagai array bit. Mari kita memiliki pendekatan dengan contoh:Katakanlah
str equals "test"
dan seterusnya .. sampai kita menemukan bit yang sudah diset di checker untuk karakter tertentu melalui kondisi
Semoga ini bisa membantu
sumber
Ada beberapa jawaban bagus yang sudah disediakan di atas. Jadi saya tidak ingin mengulangi apa yang sudah dikatakan semuanya. Tetapi memang ingin menambahkan beberapa hal untuk membantu dengan program di atas karena saya hanya bekerja melalui program yang sama dan memiliki beberapa pertanyaan tetapi setelah menghabiskan waktu, saya memiliki kejelasan lebih lanjut tentang program ini.
Pertama-tama "pemeriksa" digunakan untuk melacak karakter yang sudah dilalui dalam String untuk melihat apakah ada karakter yang diulang.
Sekarang "checker" adalah tipe data int sehingga hanya dapat memiliki 32 bit atau 4 byte (tergantung platform) sehingga program ini hanya dapat bekerja dengan benar untuk set karakter dalam kisaran 32 karakter. Itulah alasannya, program ini mengurangi 'a' dari masing-masing karakter untuk membuat program ini berjalan hanya untuk karakter huruf kecil. Namun, jika Anda mencampur huruf besar dan kecil maka itu tidak akan berhasil.
Omong-omong, jika Anda tidak mengurangi 'a' dari setiap karakter (lihat pernyataan di bawah) maka program ini akan bekerja dengan benar untuk hanya String dengan karakter huruf besar atau String dengan karakter huruf kecil saja. Jadi cakupan program di atas meningkat dari hanya karakter huruf kecil ke karakter huruf besar juga, tetapi mereka tidak dapat dicampur bersama.
Namun saya ingin menulis program generik menggunakan Operasi Bitwise yang seharusnya berfungsi untuk setiap karakter ASCII tanpa khawatir tentang huruf besar, huruf kecil, angka, atau karakter khusus apa pun. Untuk melakukan ini, "pemeriksa" kami harus cukup besar untuk menyimpan 256 karakter (ukuran Set Karakter ASCII). Tetapi sebuah int di Java tidak akan berfungsi karena ia hanya dapat menyimpan 32 bit. Oleh karena itu dalam program di bawah ini, saya menggunakan kelas BitSet yang tersedia di JDK yang dapat memiliki ukuran apa pun yang ditetapkan pengguna saat instantiating objek BitSet.
Berikut adalah program yang melakukan hal yang sama seperti program di atas yang ditulis menggunakan operator Bitwise tetapi program ini akan bekerja untuk sebuah String dengan karakter apa pun dari rangkaian karakter ASCII.
sumber
for(int i = 0; i < s.length(); i++) { int charVal = s.charAt(i); if(tracker.get(charVal)) { return false; } tracker.set(charVal); }
Membaca jawaban Ivan di atas sangat membantu saya, walaupun saya akan mengatakannya dengan agak berbeda.
The
<<
dalam(1 << val)
adalah operator sedikit pergeseran. Dibutuhkan1
(yang dalam biner direpresentasikan sebagai000000001
, dengan nol sebelumnya sebanyak yang Anda suka / dialokasikan oleh memori) dan menggesernya ke kiri olehval
spasi. Karena kita mengasumsikan hanya az dan mengurangia
setiap kali, setiap huruf akan memiliki nilai 0-25, yang akan menjadi indeks surat itu dari kanan dalamchecker
representasi boolean bilangan bulat, karena kita akan memindahkan1
ke kiri dalamchecker
val
waktu.Pada akhir setiap pemeriksaan, kami melihat
|=
operator. Ini menggabungkan dua angka biner, menggantikan semua0
dengan1
jika1
ada di salah satu operan di indeks itu. Di sini, itu berarti bahwa di mana pun1
ada(1 << val)
, yang1
akan disalin ke dalamchecker
, sementara semuachecker
1 yang ada akan dilestarikan.Seperti yang bisa Anda tebak,
1
fungsi di sini sebagai bendera boolean untuk true. Ketika kita memeriksa untuk melihat apakah suatu karakter sudah terwakili dalam string, kita membandingkanchecker
, yang pada titik ini pada dasarnya adalah array dari boolean flags (1
values) pada indeks karakter yang telah diwakili, dengan apa yang pada dasarnya adalah array dari nilai boolean dengan1
bendera pada indeks karakter saat ini.The
&
Operator menyelesaikan cek ini. Mirip dengan|=
,&
operator akan menyalin1
hanya jika kedua operan memiliki1
indeks tersebut. Jadi, pada dasarnya, hanya bendera yang sudah adachecker
yang juga diwakili(1 << val)
akan disalin. Dalam hal ini, itu berarti hanya jika karakter saat ini telah diwakili akan ada1
hadiah di mana saja di hasilchecker & (1 << val)
. Dan jika a1
hadir di mana saja dalam hasil operasi itu, maka nilai boolean yang dikembalikan adalah> 0
, dan metode mengembalikan false.Ini, saya menduga, mengapa vektor bit juga disebut bit array . Karena, meskipun mereka bukan tipe data array, mereka dapat digunakan mirip dengan cara array digunakan untuk menyimpan bendera boolean.
sumber
Penjelasan Sederhana (dengan kode JS di bawah)
32-bit
DEC64
untuk JS.0th
indeks jika kita temukana
dalam string,1st
untukb
& seterusnya.Ringkasan operasi:
checker
&index
karakterInt-32-Arrays
if
output dari operasi itu1
output == 1
checker
variabel memiliki yang agak indeks-th tertentu set di kedua arrayoutput == 0
checker
&index
karakter1
checker
Asumsi:
a
is97
Diberikan di bawah ini adalah kode sumber JavaScript .
Perhatikan bahwa dalam JS, meskipun bilangan bulat 64 bit, operasi yang bijak selalu dilakukan pada 32 bit.
Contoh: Jika stringnya adalah
aa
:i = 0
i = 1
sumber
Mari kita memecah baris kode demi baris.
pemeriksa int = 0; Kami sedang memulai pemeriksa yang akan membantu kami menemukan nilai duplikat.
int val = str.charAt (i) - 'a'; Kami mendapatkan nilai ASCII dari karakter di posisi ke-i dari string dan mengurangkannya dengan nilai ASCII dari 'a'. Karena asumsi adalah bahwa string adalah karakter yang lebih rendah saja, jumlah karakter dalam dibatasi hingga 26. Hece, nilai 'val' akan selalu>> 0.
if ((checker & (1 << val))> 0) return false;
checker | = (1 << val);
Sekarang ini bagian yang sulit. Mari kita perhatikan contoh dengan string "abcda". Ini idealnya akan kembali salah.
Untuk iterasi loop 1:
Pemeriksa: 0000000000000000000000000000000000
val: 97-97 = 0
1 << 0: 00000000000000000000000000000001
pemeriksa & (1 << val): 0000000000000000000000000000000000 tidak> 0
Oleh karena itu pemeriksa: 00000000000000000000000000000001
Untuk iterasi loop 2:
Pemeriksa: 00000000000000000000000000000001
val: 98-97 = 1
1 << 0: 0000000000000000000000000000000010
pemeriksa & (1 << val): 0000000000000000000000000000000000 tidak> 0
Oleh karena itu pemeriksa: 0000000000000000000000000000000011
Untuk iterasi loop 3:
Pemeriksa: 00000000000000000000000000000011
val: 99-97 = 0
1 << 0: 00000000000000000000000000000100100
pemeriksa & (1 << val): 0000000000000000000000000000000000 tidak> 0
Oleh karena itu pemeriksa: 00000000000000000000000000000111
Untuk iterasi loop 4:
Pemeriksa: 00000000000000000000000000000111
val: 100-97 = 0
1 << 0: 00000000000000000000000000001000
pemeriksa & (1 << val): 0000000000000000000000000000000000 tidak> 0
Oleh karena itu pemeriksa: 00000000000000000000000000001111
Untuk iterasi loop 5:
Pemeriksa: 00000000000000000000000000001111
val: 97-97 = 0
1 << 0: 00000000000000000000000000000001
pemeriksa & (1 << val): 0000000000000000000000000000000001 adalah> 0
Karena itu kembalikan salah.
sumber
sumber
Posting Sebelumnya menjelaskan dengan baik apa yang dilakukan oleh kode blok dan saya ingin menambahkan Solusi sederhana saya menggunakan struktur data java BitSet:
sumber
Cara saya mengerti menggunakan Javascript. Mengasumsikan input
var inputChar = "abca"; //find if inputChar has all unique characters
Ayo mulai
Line 4: int val = str.charAt(i) - 'a';
Dalam Javascript Misalnya:
"a".charCodeAt().toString(2)
mengembalikan 1100001checker = 1100001 | checker;
// checker menjadi 1100001 (Dalam representasi 32 bit menjadi 000000000 ..... 00001100001)Tetapi saya ingin bitmask saya (
int checker
) untuk mengatur hanya satu bit, tetapi checker adalah 1100001Mari kita gunakan
val
yang diatur ulangJalur 5 dan Jalur 6 menjelaskan jawaban @van dengan baik
sumber
Untuk jaga-jaga jika ada yang mencari kotlin setara dengan karakter unik dalam string menggunakan bit vector
Ref: https://www.programiz.com/kotlin-programming/bitwise
sumber