私はビットベクトルがこれを行うためにどのように機能するかについて混乱しています(ビットベクトルにあまり慣れていません)。以下にコードを示します。誰かが私にこれを説明してもらえますか?
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;
}
特に、checker
は何をしていますか?
_int checker
_は、ビットのストレージとしてここで使用されます。整数値のすべてのビットはフラグとして扱うことができるため、最終的にint
はビット(フラグ)の配列になります。コードの各ビットは、ビットのインデックスを持つ文字が文字列で見つかったかどうかを示します。同じ理由で、int
の代わりにビットベクトルを使用することもできます。それらの間には2つの違いがあります。
サイズ。 int
のサイズは固定で、通常は4バイトで、8 * 4 = 32ビット(フラグ)を意味します。通常、ビットベクトルは異なるサイズにするか、コンストラクタでサイズを指定する必要があります。
[〜#〜] api [〜#〜]。ビットベクトルを使用すると、おそらく次のようなコードが読みやすくなります。
vector.SetFlag(4, true); // set flag at index 4 as true
int
の場合、低レベルのビットロジックコードがあります。
checker |= (1 << 5); // set flag at index 5 to true
また、ビットを使用した操作は非常に低レベルであり、CPUによってそのまま実行できるため、おそらくint
は少し高速になる可能性があります。 BitVectorでは、暗号化コードを少し少なくすることができ、さらに多くのフラグを保存できます。
将来の参照用:ビットベクトルは、bitSetまたはbitArrayとも呼ばれます。さまざまな言語/プラットフォームのこのデータ構造へのリンクを次に示します。
私が読んでいるのと同じ本からこのコードを手に入れたという疑いがあります...ここのコード自体は、演算子-| =、&、および<<通常使用されない私たち素人-著者は、プロセスの説明や、ここに含まれる実際のメカニックスの説明に余分な時間を費やすことはありませんでした。私はこのスレッドに関する最初の回答に最初は満足していましたが、抽象レベルでのみでした。もっと具体的な説明が必要だと感じたので、私はそれに戻りました。1つが欠けているといつも不安な気持ちになります。
この演算子<<は左ビット単位のシフターであり、その数値またはオペランドのバイナリ表現を取り、バイナリのみの10進数のように右側のオペランドまたは数値で指定された多くの場所にシフトします。 10を基点としてではなく、多くの場所を上に移動するときに2を基数で乗算しているため、右側の数字は指数であり、左側の数字は2の基数倍です。
この演算子| =は、左側のオペランドを取り、ORを右側のオペランドと取ります。そして、この演算子は、両方のオペランドのビットを左右に取ります。
したがって、ここにあるのは、チェッカーが対応するビットの文字の指定されたバイナリ値で(checker |= (1 << val)
)を取得するたびに32ビットのバイナリ番号に格納されているハッシュテーブルですtrueに設定します。文字の値は、チェッカー(checker & (1 << val)) > 0
)でand'dされます。0より大きい場合、2つの同一のビットがtrueに設定され、一緒にtrueまたは '1が返されるため、重複していることがわかります。 」。
それぞれが小文字に対応する26のバイナリの場所があります-著者は、文字列に小文字のみが含まれると仮定したと言いました-これは、消費するために残っている場所が(32ビット整数で)6つしかないためです衝突する
00000000000000000000000000000001 a 2^0
00000000000000000000000000000010 b 2^1
00000000000000000000000000000100 c 2^2
00000000000000000000000000001000 d 2^3
00000000000000000000000000010000 e 2^4
00000000000000000000000000100000 f 2^5
00000000000000000000000001000000 g 2^6
00000000000000000000000010000000 h 2^7
00000000000000000000000100000000 i 2^8
00000000000000000000001000000000 j 2^9
00000000000000000000010000000000 k 2^10
00000000000000000000100000000000 l 2^11
00000000000000000001000000000000 m 2^12
00000000000000000010000000000000 n 2^13
00000000000000000100000000000000 o 2^14
00000000000000001000000000000000 p 2^15
00000000000000010000000000000000 q 2^16
00000000000000100000000000000000 r 2^17
00000000000001000000000000000000 s 2^18
00000000000010000000000000000000 t 2^19
00000000000100000000000000000000 u 2^20
00000000001000000000000000000000 v 2^21
00000000010000000000000000000000 w 2^22
00000000100000000000000000000000 x 2^23
00000001000000000000000000000000 y 2^24
00000010000000000000000000000000 z 2^25
したがって、入力文字列「azya」の場合、ステップごとに移動します
文字列「a」
a =00000000000000000000000000000001
checker=00000000000000000000000000000000
checker='a' or checker;
// checker now becomes = 00000000000000000000000000000001
checker=00000000000000000000000000000001
a and checker=0 no dupes condition
文字列「az」
checker=00000000000000000000000000000001
z =00000010000000000000000000000000
z and checker=0 no dupes
checker=z or checker;
// checker now becomes 00000010000000000000000000000001
文字列「azy」
checker= 00000010000000000000000000000001
y = 00000001000000000000000000000000
checker and y=0 no dupes condition
checker= checker or y;
// checker now becomes = 00000011000000000000000000000001
文字列「azya」
checker= 00000011000000000000000000000001
a = 00000000000000000000000000000001
a and checker=1 we have a dupe
現在、duplicateを宣言しています
また、あなたの例は本から出てくると思います Cracking The Code Interview と私の答えはこの文脈に関連しています。
このアルゴリズムを使用して問題を解決するには、aからz(小文字)にのみ文字を渡すことを認める必要があります。
26文字しかないため、使用するエンコードテーブルで適切にソートされているため、潜在的な差str.charAt(i) - 'a'
が32(int変数checker
のサイズよりも小さいことが保証されます。 )。
Snowbearで説明したように、checker
変数をビットの配列として使用しようとしています。例でアプローチしてみましょう:
まあ言ってみれば str equals "test"
チェッカー== 0(00000000000000000000000000000000)
In ASCII, val = str.charAt(i) - 'a' = 116 - 97 = 19
What about 1 << val ?
1 == 00000000000000000000000000000001
1 << 19 == 00000000000010000000000000000000
checker |= (1 << val) means checker = checker | (1 << val)
so checker = 00000000000000000000000000000000 | 00000000000010000000000000000000
checker == 524288 (00000000000010000000000000000000)
チェッカー== 524288(00000000000010000000000000000000)
val = 101 - 97 = 4
1 == 00000000000000000000000000000001
1 << 4 == 00000000000000000000000000010000
checker |= (1 << val)
so checker = 00000000000010000000000000000000 | 00000000000000000000000000010000
checker == 524304 (00000000000010000000000000010000)
など..条件を介して特定の文字のチェッカーに既に設定されているビットが見つかるまで
(checker & (1 << val)) > 0
それが役に立てば幸い
これらの答えはすべてこれがどのように機能するかを説明していると思いますが、いくつかの変数の名前を変更し、他の変数を追加し、コメントを追加することで、私がそれをどのように見たのかについて自分の意見を述べたいと感じました:
public static boolean isUniqueChars(String str) {
/*
checker is the bit array, it will have a 1 on the character index that
has appeared before and a 0 if the character has not appeared, you
can see this number initialized as 32 0 bits:
00000000 00000000 00000000 00000000
*/
int checker = 0;
//loop through each String character
for (int i = 0; i < str.length(); ++i) {
/*
a through z in ASCII are charactets numbered 97 through 122, 26 characters total
with this, you get a number between 0 and 25 to represent each character index
0 for 'a' and 25 for 'z'
renamed 'val' as 'characterIndex' to be more descriptive
*/
int characterIndex = str.charAt(i) - 'a'; //char 'a' would get 0 and char 'z' would get 26
/*
created a new variable to make things clearer 'singleBitOnPosition'
It is used to calculate a number that represents the bit value of having that
character index as a 1 and the rest as a 0, this is achieved
by getting the single digit 1 and shifting it to the left as many
times as the character index requires
e.g. character 'd'
00000000 00000000 00000000 00000001
Shift 3 spaces to the left (<<) because 'd' index is number 3
1 shift: 00000000 00000000 00000000 00000010
2 shift: 00000000 00000000 00000000 00000100
3 shift: 00000000 00000000 00000000 00001000
Therefore the number representing 'd' is
00000000 00000000 00000000 00001000
*/
int singleBitOnPosition = 1 << characterIndex;
/*
This peforms an AND between the checker, which is the bit array
containing everything that has been found before and the number
representing the bit that will be turned on for this particular
character. e.g.
if we have already seen 'a', 'b' and 'd', checker will have:
checker = 00000000 00000000 00000000 00001011
And if we see 'b' again:
'b' = 00000000 00000000 00000000 00000010
it will do the following:
00000000 00000000 00000000 00001011
& (AND)
00000000 00000000 00000000 00000010
-----------------------------------
00000000 00000000 00000000 00000010
Since this number is different than '0' it means that the character
was seen before, because on that character index we already have a
1 bit value
*/
if ((checker & singleBitOnPosition) > 0) {
return false;
}
/*
Remember that
checker |= singleBitOnPosition is the same as
checker = checker | singleBitOnPosition
Sometimes it is easier to see it expanded like that.
What this achieves is that it builds the checker to have the new
value it hasnt seen, by doing an OR between checker and the value
representing this character index as a 1. e.g.
If the character is 'f' and the checker has seen 'g' and 'a', the
following will happen
'f' = 00000000 00000000 00000000 00100000
checker(seen 'a' and 'g' so far) = 00000000 00000000 00000000 01000001
00000000 00000000 00000000 00100000
| (OR)
00000000 00000000 00000000 01000001
-----------------------------------
00000000 00000000 00000000 01100001
Therefore getting a new checker as 00000000 00000000 00000000 01100001
*/
checker |= singleBitOnPosition;
}
return true;
}
上記のIvanの答えを読むことは本当に助けになりましたが、言い方は多少異なります。
<<
の(1 << val)
はビットシフト演算子です。 1
(バイナリで000000001
として表され、好きなだけ多くの先行ゼロがメモリによって割り当てられる)を取り、それをval
スペースだけ左にシフトします。 azのみを想定し、毎回a
を減算するので、各文字の値は0-25になります。これは、1
を左に移動するため、checker
整数のブール表現の右からその文字のインデックスになりますchecker
val
回。
各チェックの最後に、|=
演算子があります。これは2つの2進数をマージし、そのインデックスのいずれかのオペランドに0
が存在する場合、すべての1
を1
に置き換えます。ここで、それは、1
が(1 << val)
のどこに存在する場合でも、その1
はchecker
にコピーされ、checker
の既存の1はすべて保持されることを意味します。
おそらく推測できるように、ここで1
はtrueのブールフラグとして機能します。文字が既に文字列で表されているかどうかを確認するとき、checker
を比較します。この変数は、この時点で、すでに表されている文字のインデックスにあるブールフラグ(1
値)の配列です。現在の文字のインデックスに1
フラグを付けたブール値の配列。
&
演算子はこのチェックを実行します。 |=
と同様に、&
演算子は、両方のオペランドのインデックスに1
がある場合、1
onlyをコピーします。そのため、本質的には(1 << val)
でも表されるchecker
に既に存在するフラグのみがコピーされます。この場合、現在の文字がすでに表現されている場合にのみ、checker & (1 << val)
の結果のどこかに1
が存在することを意味します。また、1
がその操作の結果のどこかに存在する場合、返されるブール値の値は> 0
であり、メソッドはfalseを返します。
これが、ビットベクトルがビット配列とも呼ばれる理由です。配列データ型ではありませんが、ブールフラグを格納するために配列を使用する方法と同様に使用できるためです。
上記で既に提供された優れた回答がいくつかあります。だから、私はすでに言ったことすべてを繰り返したくありません。しかし、上記のプログラムに役立つものをいくつか追加したいと思ったのは、同じプログラムを試したばかりで、いくつか質問がありましたが、しばらく時間を費やした後、このプログラムについてより明確になったからです。
まず、「チェッカー」を使用して、文字列で既にトラバースされている文字を追跡し、繰り返される文字があるかどうかを確認します。
現在、「チェッカー」はintデータ型であるため、32ビットまたは4バイト(プラットフォームに応じて)しか持てないため、このプログラムは32文字の範囲内の文字セットに対してのみ正しく動作します。それが理由で、このプログラムは小文字のみでこのプログラムを実行するために、各文字から「a」を引きます。ただし、小文字と大文字を混在させると機能しません。
ちなみに、各文字から「a」を減算しない場合(以下のステートメントを参照)、このプログラムは、大文字の文字列のみ、または小文字のみの文字列に対して正しく動作します。そのため、上記のプログラムの範囲は、小文字から大文字まで増加しますが、それらを混在させることはできません。
int val = str.charAt(i) - 'a';
ただし、大文字、小文字、数字、または特殊文字を気にせずに任意のASCII文字で動作するはずのBitwise Operationを使用して汎用プログラムを作成したかったのです。これを行うには、チェッカー」は256文字(ASCII文字セットサイズ)を格納するのに十分な大きさでなければなりません。ただし、Javaのintは32ビットしか格納できないため機能しません。したがって、以下のプログラムでは、 JDKで使用可能なBitSetクラス。BitSetオブジェクトのインスタンス化中にユーザー定義のサイズを渡すことができます。
以下は、ビットごとの演算子を使用して記述された上記のプログラムと同じことを行うプログラムですが、このプログラムはASCII文字セットの任意の文字を含む文字列に対して機能します。
public static boolean isUniqueStringUsingBitVectorClass(String s) {
final int ASCII_CHARACTER_SET_SIZE = 256;
final BitSet tracker = new BitSet(ASCII_CHARACTER_SET_SIZE);
// if more than 256 ASCII characters then there can't be unique characters
if(s.length() > 256) {
return false;
}
//this will be used to keep the location of each character in String
final BitSet charBitLocation = new BitSet(ASCII_CHARACTER_SET_SIZE);
for(int i = 0; i < s.length(); i++) {
int charVal = s.charAt(i);
charBitLocation.set(charVal); //set the char location in BitSet
//check if tracker has already bit set with the bit present in charBitLocation
if(tracker.intersects(charBitLocation)) {
return false;
}
//set the tracker with new bit from charBitLocation
tracker.or(charBitLocation);
charBitLocation.clear(); //clear charBitLocation to store bit for character in the next iteration of the loop
}
return true;
}
簡単な説明(JSコードを使用)
32-bit
ですDEC64
。a
が見つかった場合は0th
インデックスを設定し、b
には1st
などを設定します。操作の概要:
checker
とindex
の間の操作を実行しますInt-32-Arrays
if
を確認してください。操作の出力は1
でしたoutput == 1
checker
変数には、両方の配列でその特定のインデックス番目のビットが設定されていますoutput == 0
checker
とindex
の間で[〜#〜] or [〜#〜]操作を実行する1
に更新しますchecker
に割り当てます仮定:
a
のコードは97
です以下にJavaScriptソースコードを示します。
function checkIfUniqueChars (str) {
var checker = 0; // 32 or 64 bit integer variable
for (var i = 0; i< str.length; i++) {
var index = str[i].charCodeAt(0) - 96;
var bitRepresentationOfIndex = 1 << index;
if ( (checker & bitRepresentationOfIndex) > 1) {
console.log(str, false);
return false;
} else {
checker = (checker | bitRepresentationOfIndex);
}
}
console.log(str, true);
return true;
}
checkIfUniqueChars("abcdefghi"); // true
checkIfUniqueChars("aabcdefghi"); // false
checkIfUniqueChars("abbcdefghi"); // false
checkIfUniqueChars("abcdefghii"); // false
checkIfUniqueChars("abcdefghii"); // false
注 JSでは、整数は64ビットですが、ビット単位の演算は常に32ビットで行われます。
例:文字列がaa
の場合:
// checker is intialized to 32-bit-Int(0)
// therefore, checker is
checker= 00000000000000000000000000000000
i =
str[0] is 'a'
str[i].charCodeAt(0) - 96 = 1
checker 'AND' 32-bit-Int(1) = 00000000000000000000000000000000
Boolean(0) == false
// So, we go for the '`OR`' operation.
checker = checker OR 32-bit-Int(1)
checker = 00000000000000000000000000000001
i = 1
str[1] is 'a'
str[i].charCodeAt(0) - 96 = 1
checker= 00000000000000000000000000000001
a = 00000000000000000000000000000001
checker 'AND' 32-bit-Int(1) = 00000000000000000000000000000001
Boolean(1) == true
// We've our duplicate now
コードを行ごとに分解してみましょう。
int checker = 0;重複する値を見つけるのに役立つチェッカーを開始しています。
int val = str.charAt(i)-'a';文字列の「i」番目の位置にある文字のASCII値ASCII 'a'の値を使用して減算します。文字列は下の文字のみであると仮定されているため、文字数は26に制限されます。常に> = 0になります。
if((checker&(1 << val))> 0)return false;
チェッカー(1 << val);)==
今、これはトリッキーな部分です。文字列「abcda」の例を考えてみましょう。これは理想的にはfalseを返すはずです。
For loop iteration 1:
チェッカー:00000000000000000000000000000000
val:97-97 = 0
1 << 0:00000000000000000000000000000001
チェッカー&(1 << val):00000000000000000000000000000000は> 0ではありません
したがって、チェッカー:00000000000000000000000000000001
For loop iteration 2:
チェッカー:00000000000000000000000000000001
val:98-97 = 1
1 << 0:00000000000000000000000000000010
チェッカー&(1 << val):00000000000000000000000000000000は> 0ではありません
したがって、チェッカー:00000000000000000000000000000011
For loop iteration 3:
チェッカー:00000000000000000000000000000011
val:99-97 = 0
1 << 0:00000000000000000000000000000100
チェッカー&(1 << val):00000000000000000000000000000000は> 0ではありません
したがって、チェッカー:00000000000000000000000000000111
For loop iteration 4:
チェッカー:00000000000000000000000000000111
val:100-97 = 0
1 << 0:00000000000000000000000000001000
チェッカー&(1 << val):00000000000000000000000000000000は> 0ではありません
したがって、チェッカー:00000000000000000000000000001111
For loop iteration 5:
チェッカー:00000000000000000000000000001111
val:97-97 = 0
1 << 0:00000000000000000000000000000001
チェッカー&(1 << val):00000000000000000000000000000001は> 0
したがって、falseを返します。
public static void main (String[] args)
{
//In order to understand this algorithm, it is necessary to understand the following:
//int checker = 0;
//Here we are using the primitive int almost like an array of size 32 where the only values can be 1 or 0
//Since in Java, we have 4 bytes per int, 8 bits per byte, we have a total of 4x8=32 bits to work with
//int val = str.charAt(i) - 'a';
//In order to understand what is going on here, we must realize that all characters have a numeric value
for (int i = 0; i < 256; i++)
{
char val = (char)i;
System.out.print(val);
}
//The output is something like:
// !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
//There seems to be ~15 leading spaces that do not copy paste well, so I had to use real spaces instead
//To only print the characters from 'a' on forward:
System.out.println();
System.out.println();
for (int i=0; i < 256; i++)
{
char val = (char)i;
//char val2 = val + 'a'; //incompatible types. required: char found: int
int val2 = val + 'a'; //shift to the 'a', we must use an int here otherwise the compiler will complain
char val3 = (char)val2; //convert back to char. there should be a more elegant way of doing this.
System.out.print(val3);
}
//Notice how the following does not work:
System.out.println();
System.out.println();
for (int i=0; i < 256; i++)
{
char val = (char)i;
int val2 = val - 'a';
char val3 = (char)val2;
System.out.print(val3);
}
//I'm not sure why this spills out into 2 lines:
//EDIT I cant seem to copy this into stackoverflow!
System.out.println();
System.out.println();
//So back to our original algorithm:
//int val = str.charAt(i) - 'a';
//We convert the i'th character of the String to a character, and shift it to the right, since adding shifts to the right and subtracting shifts to the left it seems
//if ((checker & (1 << val)) > 0) return false;
//This line is quite a mouthful, lets break it down:
System.out.println(0<<0);
//00000000000000000000000000000000
System.out.println(0<<1);
//00000000000000000000000000000000
System.out.println(0<<2);
//00000000000000000000000000000000
System.out.println(0<<3);
//00000000000000000000000000000000
System.out.println(1<<0);
//00000000000000000000000000000001
System.out.println(1<<1);
//00000000000000000000000000000010 == 2
System.out.println(1<<2);
//00000000000000000000000000000100 == 4
System.out.println(1<<3);
//00000000000000000000000000001000 == 8
System.out.println(2<<0);
//00000000000000000000000000000010 == 2
System.out.println(2<<1);
//00000000000000000000000000000100 == 4
System.out.println(2<<2);
// == 8
System.out.println(2<<3);
// == 16
System.out.println("3<<0 == "+(3<<0));
// != 4 why 3???
System.out.println(3<<1);
//00000000000000000000000000000011 == 3
//shift left by 1
//00000000000000000000000000000110 == 6
System.out.println(3<<2);
//00000000000000000000000000000011 == 3
//shift left by 2
//00000000000000000000000000001100 == 12
System.out.println(3<<3);
// 24
//It seems that the - 'a' is not necessary
//Back to if ((checker & (1 << val)) > 0) return false;
//(1 << val means we simply shift 1 by the numeric representation of the current character
//the bitwise & works as such:
System.out.println();
System.out.println();
System.out.println(0&0); //0
System.out.println(0&1); //0
System.out.println(0&2); //0
System.out.println();
System.out.println();
System.out.println(1&0); //0
System.out.println(1&1); //1
System.out.println(1&2); //0
System.out.println(1&3); //1
System.out.println();
System.out.println();
System.out.println(2&0); //0
System.out.println(2&1); //0 0010 & 0001 == 0000 = 0
System.out.println(2&2); //2 0010 & 0010 == 2
System.out.println(2&3); //2 0010 & 0011 = 0010 == 2
System.out.println();
System.out.println();
System.out.println(3&0); //0 0011 & 0000 == 0
System.out.println(3&1); //1 0011 & 0001 == 0001 == 1
System.out.println(3&2); //2 0011 & 0010 == 0010 == 2, 0&1 = 0 1&1 = 1
System.out.println(3&3); //3 why?? 3 == 0011 & 0011 == 3???
System.out.println(9&11); // should be... 1001 & 1011 == 1001 == 8+1 == 9?? yay!
//so when we do (1 << val), we take 0001 and shift it by say, 97 for 'a', since any 'a' is also 97
//why is it that the result of bitwise & is > 0 means its a dupe?
//lets see..
//0011 & 0011 is 0011 means its a dupe
//0000 & 0011 is 0000 means no dupe
//0010 & 0001 is 0011 means its no dupe
//hmm
//only when it is all 0000 means its no dupe
//so moving on:
//checker |= (1 << val)
//the |= needs exploring:
int x = 0;
int y = 1;
int z = 2;
int a = 3;
int b = 4;
System.out.println("x|=1 "+(x|=1)); //1
System.out.println(x|=1); //1
System.out.println(x|=1); //1
System.out.println(x|=1); //1
System.out.println(x|=1); //1
System.out.println(y|=1); // 0001 |= 0001 == ?? 1????
System.out.println(y|=2); // ??? == 3 why??? 0001 |= 0010 == 3... hmm
System.out.println(y); //should be 3??
System.out.println(y|=1); //already 3 so... 0011 |= 0001... maybe 0011 again? 3?
System.out.println(y|=2); //0011 |= 0010..... hmm maybe.. 0011??? still 3? yup!
System.out.println(y|=3); //0011 |= 0011, still 3
System.out.println(y|=4); //0011 |= 0100.. should be... 0111? so... 11? no its 7
System.out.println(y|=5); //so we're at 7 which is 0111, 0111 |= 0101 means 0111 still 7
System.out.println(b|=9); //so 0100 |= 1001 is... seems like xor?? or just or i think, just or... so its 1101 so its 13? YAY!
//so the |= is just a bitwise OR!
}
public static boolean isUniqueChars(String str) {
int checker = 0;
for (int i = 0; i < str.length(); ++i) {
int val = str.charAt(i) - 'a'; //the - 'a' is just smoke and mirrors! not necessary!
if ((checker & (1 << val)) > 0) return false;
checker |= (1 << val);
}
return true;
}
public static boolean is_unique(String input)
{
int using_int_as_32_flags = 0;
for (int i=0; i < input.length(); i++)
{
int numeric_representation_of_char_at_i = input.charAt(i);
int using_0001_and_shifting_it_by_the_numeric_representation = 1 << numeric_representation_of_char_at_i; //here we shift the bitwise representation of 1 by the numeric val of the character
int result_of_bitwise_and = using_int_as_32_flags & using_0001_and_shifting_it_by_the_numeric_representation;
boolean already_bit_flagged = result_of_bitwise_and > 0; //needs clarification why is it that the result of bitwise & is > 0 means its a dupe?
if (already_bit_flagged)
return false;
using_int_as_32_flags |= using_0001_and_shifting_it_by_the_numeric_representation;
}
return true;
}
以前の投稿では、コードブロックが何を行うのかをよく説明しており、BitSet Java Data structureを使用して簡単なソリューションを追加したいと思います。
private static String isUniqueCharsUsingBitSet(String string) {
BitSet bitSet =new BitSet();
for (int i = 0; i < string.length(); ++i) {
int val = string.charAt(i);
if(bitSet.get(val)) return "NO";
bitSet.set(val);
}
return "YES";
}