簡體   English   中英

Java 新手 - 試圖理解:檢查器 |= (1 << val)

[英]new to java - trying to understand: checker |= (1 << val)

以下代碼將檢查字符串中是否有任何重復字符,但我不明白 if 子句:

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;
    }

我試圖查找一些參考資料,我是位移位的新手,我所了解的是 << 向左或向右移動二進制數。 你能向我解釋檢查器 |= (1 << val) 是如何工作的嗎? 還有那個“if”語句。

我也在閱讀《 破解代碼面試》這本書,最終在谷歌上搜索了清晰的解釋。 終於明白了這個概念。

這是方法。

筆記 :

  1. 我們將假設,在下面的代碼中,字符串只是小寫的“a”到“z”。 這將允許我們只使用一個 int。

  2. Java整數的大小為32

  3. 小寫字母的數量26

所以我們可以清楚地在一個整數內以十進制表示法設置 0/1(真或假)值。

  1. 它類似於boolvisited[32] bool使用 1 個字節。 因此,您需要 32 個字節來存儲 bool 訪問 [32]。

  2. 位掩碼是對此的空間優化。

開始吧 :

  1. 您正在遍歷字符串中的所有字符。
  2. 假設在第 i 次迭代中您找到了字符 'b' 。 你計算它的基於 0 的 index

int val = str.charAt(i) - 'a';

對於'b' 它是 1 即 98-97 。

  1. 現在使用左移運算符,我們找到 2^1 => 2 的值。

(1 << val) // 1<<1 => 10(binary)

現在讓我們看看按位&是如何工作的

0 & 0 -> 0
0 & 1 -> 0
1 & 0 -> 0
1 & 1 -> 1

所以通過下面的代碼:

(checker & (1 << val))

我們檢查 checker[val] == 0 是否。 假設我們已經遇到了'b'。

check = 0000 0000 0000 0000 0000 1000 1000 0010   &  
'b'   = 0000 0000 0000 0000 0000 0000 0000 0010 
 ----------------------------------------------
result= 0000 0000 0000 0000 0000 0000 0000 0010

即十進制值 = 2,即 >0

所以你終於我們理解了這部分。

 if ((checker & (1 << val)) > 0) 
                return false;
  1. 現在,如果沒有遇到 'b',那么我們使用按位 OR 設置檢查器的第二位

(這部分稱為位掩碼。)

OR的真值表

0 | 0 -> 0
0 | 1 -> 1
1 | 0 -> 1
1 | 1 -> 1

所以

check = 0000 0000 0000 0000 0000 1000 1000 0000   |  
'b'   = 0000 0000 0000 0000 0000 0000 0000 0010 
 ----------------------------------------------
result= 0000 0000 0000 0000 0000 1000 1000 0010

所以這簡化了這部分:

checker |= (1 << val);  // checker = checker |  (1 << val);

我希望這對某人有所幫助!

好像我參加聚會遲到了,但讓我來解釋一下。

首先是 AND 即 & 操作:

0 & 0 = 0
1 & 0 = 0
0 & 1 = 0
1 & 1 = 1

所以基本上,如果你得到一點,並且你想知道它是 1 還是 0,你只需將它與 1 相加。如果結果是 1,那么你有一個 1,否則你有 0。我們將使用這個& 下面的屬性。

OR 即 | 手術

0 | 0 = 0
1 | 0 = 1
0 | 1 = 1
1 | 1 = 1  

所以基本上,如果你得到了一點,並且你想對它做一些事情以便輸出總是 1,那么你做一個 | 1 與它。

現在,在 Java 中, int類型是 4 個字節,即 32 位。 因此,我們可以使用int本身作為數據結構來存儲 32 個狀態或布爾值,因為一個位可以是 0 或 1,即假或真。 由於我們假設我們的字符串僅由小寫字符組成,因此我們在 int 中有足夠的空間來為 26 個字符中的每一個存儲一個布爾值!

因此,首先我們將我們稱為checker數據結構初始化為 0,它只是 32 個零: 0000000000000000000000

到現在為止還挺好?

現在我們遍歷我們的字符串,對於每個字符,首先我們得到字符的整數表示。

int val = str.charAt(i) - 'a';

我們從中減去a是因為我們希望我們的整數是基於 0 的。 所以如果 vals:

a = 0 i.e. `0000000000000000000000`
b = 1 i.e. `0000000000000000000001`
c = 2 i.e. `0000000000000000000010`
d = 4 i.e. `0000000000000000000100`

現在如上所示,a 是 32 個零,但其余字符有單個 1 和 31 個零。 因此,當我們使用這些字符時,我們left shift每個字符left shift 1,即 (1 << val),因此每個字符都有一個1 位和 31 個零位

a = 1 i.e. `0000000000000000000001`
b = 2 i.e. `0000000000000000000010`
c = 4 i.e. `0000000000000000000100`
d = 8 i.e. `0000000000000000001000`

我們完成了設置。 現在我們做兩件事:

  1. 首先假設所有字符都不同。 對於我們遇到的每個字符,我們希望我們的數據結構即檢查器為該字符設置 1。 所以我們使用上面描述的 OR 屬性在我們的數據結構中生成一個 1,因此我們這樣做:

     checker = checker | (1 << val);

因此,檢查器為我們遇到的每個字符存儲 1。

  1. 現在我們來到字符可以重復的部分。 所以在我們做第 1 步之前,我們要確保檢查器在當前字符對應的位置已經沒有 1。 所以我們檢查的值

    checker & (1 << val)

所以借助上面描述的 AND 屬性,如果我們從這個操作中得到一個 1,那么 checker 在那個位置已經有一個 1,這意味着我們之前一定遇到過這個字符。 所以我們立即返回false。

就是這樣 如果我們所有的 & 檢查返回 0,我們最終返回 true,這意味着沒有字符重復。

1 << val2 to the degree of val相同。 所以這是一個數字
它的二進制表示中只有一個一(一個在位置val+1 ,如果你從
數字的右邊到左邊一個)。

a |= b基本上意味着:在a設置所有二進制標志/來自
的二進制表示b (並保持在那些a其中已經設置)。

這會將右側的第 'val' 位設置為 1。

1 << val是 1 左移val次。 其余值為 0。

該行相當於checker = checker | (1 << val) checker = checker | (1 << val) 0 位的或運算什么都不做,因為x | 0 == x x | 0 == x 但是 1 的 or-ing 總是導致 1。所以這會(僅)打開那個位。

if語句類似,因為它正在檢查該位是否已經打開。 掩碼值1 << val除了單個 1 外都是 0。與 0 總是產生 0,因此結果中的大多數位都是 0。x & 1 == x,因此只有在以下情況下它才會為非零val那個位不是 0。

checker |= (1 << val)checker = checker | (1 << val)相同 checker = checker | (1 << val) <<是你說的左移。 1 << val表示它是左移1 val數字。 示例: 1 << 4是 1000。左移與乘以 2 相同。4 次左移是 4 乘以 1 乘以 2。

1 * 2 = 2 (1)
2 * 2 = 4 (2)
4 * 2 = 8 (3)
8 * 2 = 16 = (4)

| 運算符是按位或。 這就像正常或一點點。 如果我們有多個位,則對每一位執行 or 操作。 例子:

110 | 011 = 111

您可以使用它來設置標志(使位 1)。

if 條件與此類似,但具有&運算符,它是按位與。 它主要用於屏蔽二進制數。

例子:

110 | 100 = 100

因此,您的代碼僅檢查val位置的位是否為 1,然后return false ,否則將val位置的位設置為 1。

其他答案解釋了編碼運算符的用法,但我認為它們沒有觸及此代碼背后的邏輯。

基本上,代碼1 << val將二進制數中的 1 移到每個字符的唯一位置,例如

a-0001 b-0010 c-0100 d-1000

正如您所注意到的,對於不同的字符,1 的位置是不同的

checker = checker | (1 << val)

這里的檢查器是 Oring(基本上將 1 存儲在與1<<val相同的位置)所以檢查器知道已經出現了哪些字符讓我們說在出現 a,b,c,d 后checker看起來像這樣0000 1111

最后

if ((checker & (1 << val)) > 0) 

檢查該字符之前是否已經出現過,如果是,則返回false。解釋一下,您應該對AND(&) 操作有所了解。

  • 1&1->1
  • 0&0->0
  • 1&0->0

因此,檢查器當前在相應字符已經出現的地方有 1,如果一個字符出現兩次導致 1&1->1 > 0,則 if 語句中的表達式為真

這意味着對值checker(1 << val) (即 1,左移val次)進行二進制 OR 並將新創建的值保存在checker

左移( << )

將所有二進制數字左移一個空格。 有效地將數字提高到 2 的val次方或將數字乘以 2 val倍。

按位或 ( | )

在左右值的每個二進制字符中,如果兩個數字中的任何一個的位置都為1 ,則保留它。

增強分配|=

執行操作(在本例中為按位或)並將值賦給左側變量。 這適用於許多運營商,例如:-

  • a += b ,將a添加到b並將新值保存在a
  • a *= b ,將a乘以b並將新值保存在a

按位移位的工作原理如下:

示例:a=15(位表示:0000 1111)

對於操作: a<<2

它將向左旋轉 2 個位置的位表示。

所以a<<20011 1100 = 0*2^7+0*2^6+1*2^5+1*2^4+1*2^3+1*2^2+0*2^1+0*2^0 = 1*2^5+1*2^4+1*2^3+1*2^2 = 32+18+8+4=60

因此a<<2 = 60

現在:

checker & (1<<val) ,如果 1 已經存在於1<<val位置,則總是大於 0。

因此我們可以返回false

否則,我們將在 1 處分配檢查器值 1

我一直在研究算法,這就是我注意到的也可以工作。 當您手動練習時,它使算法更容易理解:

public static boolean isUniqueChars(String str) {
    if (str.length() > 26) { // Only 26 characters
        return false;
    }
    int checker = 0;
    for (int i = 0; i < str.length(); i++) {
        int val = str.charAt(i) - 'a';
        int newValue = Math.pow(2, val) // int newValue = 1 << val
        if ((checker & newValue) > 0) return false;
        checker += newValue // checker |= newValue
    }
    return true;

當我們得到val (0-25) 的值時,我們可以將 1 右移val的值,或者我們可以使用 2 的冪。

此外,只要((checker & newValue) > 0)為假,當我們將舊的檢查器值和newValue相加時,就會生成新的檢查器值。

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;
}

1 << val 使用右移運算符。 假設我們有字符 z。 z 的 ASCII 碼是 122。az 是 97-122 = 25。如果我們乘以 1*(2)^25 = 33554432。如​​果檢查器的第 26 位語句為 1,則二進制為 100000000000000000000000000000000000 1 << val)) > 0) 為真,isUniqueChar 將返回假。 否則檢查器會打開它的第 26 位。 |= 運算符(按位或和賦值運算符)執行檢查器按位 OR 10000000000000000000000000。將結果分配給檢查器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM