有人可以解释一下这段代码中如何使用移位?

时间:2017-01-23 03:48:25

标签: java python bit-manipulation

我在尝试学习Python%的同时解决了样本问题......但是我得到的问题书在Java中存在问题和解决方案,所以我试图在两者之间来回转换语言。我刚刚学会了位移的工作方式,而且我一直在盯着这段代码试图找出第5行(和8)的确切内容......我试着写下一些例子,只是通过代码行按行,但由于某种原因,它对我来说仍然不是很明显...... 请有人澄清一下吗?

另外,根据我的理解,str.charAt(i)返回一个角色对我来说真的很奇怪,然后你可以继续从另一个角色中减去它......就像申请{{} 1}}与Python中的int相同的字符?

问题:实现一个算法来确定字符串是否具有所有唯一字符。

解决方案(仅限字符a-z):

ord()

3 个答案:

答案 0 :(得分:3)

不确定。只有当str中只包含小写字母时,此代码才真正有用。

checker是一个32位整数,您使用32位中的26位来记录str中特定字母的存在。因此,位0将用于记录a的存在,位1将用于记录b的存在,依此类推至位25,这将用于记录存在的z

基本算法是逐个字符地处理str。对于每个字符,找到checker中的相应位。如果已经设置,则该字符必须第二次出现 - 因此我们可以停止处理并返回false。否则,设置该位。

如果到达字符串的末尾而没有找到任何重复的字符,则返回true

神奇之处在于以下步骤。

  • 从每个字符中减去'a'会将其转换为0到25之间的数字。
  • 符号<<是“左移”运算符,它将位模式向左移动一些位。结果是1 << val是特定位(1,2,4,8等)的位置值。
  • 符号&执行二进制AND,因此如果位checker & (1 << val)被清除,则表达式val将为0,如果已设置,则等于1 << val
  • 符号|=执行二进制OR,并将结果分配给左侧的变量。因此表达式checker |= (1 << val)设置了位val

答案 1 :(得分:2)

让我们尝试一个更简单的变化:

boolean isUniqueChars(String str) {
    boolean[] seen = new boolean[26];
    for (int i = 0; i < str.length(); i++) {
        // convert char to 0-based offset
        int index = str.charAt(i) - 'a';
        if (seen[index]) {
            // this char was seen already
            return false;
        }
        seen[index] = true;
    }
    // no duplicates found
    return true;
}

非常直率,对吧?我们创建一个布尔数组,使用字符偏移作为索引,并检查字符串中的每个字符,看看我们是否遇到过它。您发布的代码使用相同的逻辑,但改为使用更有效的位设置。

(1 << val)val转换为位索引。 checker & (1 << val)过滤掉其他索引,以便我们可以检查这一个。 (checker & (1 << val)) > 0检查索引中是否有任何值。 checker |= (1 << val)在索引处打开了位。所有其他逻辑都是相同的。

答案 2 :(得分:2)

首先,如果输入字符串包含字母“a”到“z”,则代码只能可靠地工作。

变量检查器是32位int。检查器中的每个位用作一个标志,表示存在26个字母'a'到'z'中的一个。

该行

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

通过减去字符'a'的值,将存储在str索引i的字符转换为存储在val中的整数。是的,我认为pascal具有相同的Ord('')函数。

a = 0
b = 1
c = 2
etc
etc
etc
z = 25

代码

(1 << val)

将val移位到其位位置的适当值

所以

a = 0 = 1
b = 1 = 2
c = 2 = 4
d = 3 = 8
etc
etc
z = 25 = 33554432

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

确定该位是否已在检查器中设置,表示重复的字符。如果是,则该函数返回false。

否则

checker |= (1 << val)

通过二进制OR设置检查器中的位,然后再循环。