为什么位操作比字符串操作LeetCode#476慢

时间:2017-12-11 18:11:28

标签: java bit-manipulation

我正在写一个leetCode问题,要求我输出一个整数的补码整数。 LeetCode#476

我一直认为位操作很快,因为在最后,一切都是通过位操作来完成的。但是在这个问题中,字符串方法比位操作更快,我想知道为什么。

我写了一个11ms接受的字符串操作代码。代码如下,非常直观。

class Solution {
    public int findComplement(int num) {
        String s = Integer.toBinaryString(num);
        StringBuilder sb = new StringBuilder();
        for(char c : s.toCharArray()){
            sb.append(c == '1' ? 0 : 1);
        }
        int ret = Integer.parseInt(sb.toString(), 2);
        return ret;
    }
}

我偷看了讨论,发现了一些解决问题的操作,我试了一下。然而,它被接受了13ms。以下是代码。

class Solution {
    public int findComplement(int num) {
        return ~num & ((Integer.highestOneBit(num) << 1) - 1);
    }
}

1 个答案:

答案 0 :(得分:1)

我确定LeetCode的时间安排有点可疑。

首先,我提交了几次位操作解决方案,时间从11到14毫秒不等。

然后,我提交了以下代码的各种版本,迭代次数不同:

public int findComplement(int num) {
    int ret = 0;
    for (int i = 1; i <= 2000000; i++)
        ret |= ~num & ((Integer.highestOneBit(num) << 1) - 1);
    return ret;
}

结果:

Number of iterations      Time/ms
--------------------      -------
                   1       11
                  10       17
                  20       14
                 200       32
               20000       39
             2000000      145

特别注意,20次迭代只需不到10次迭代。但总体而言,时间与迭代相比呈上升趋势。我认为LeetCode没有足够的时间调用该方法来做任何有意义的时间。

这是一种更快的方法:

public int findComplement(int num) {
    int usedBits = num;
    usedBits |= usedBits >> 1;
    usedBits |= usedBits >> 2;
    usedBits |= usedBits >> 4;
    usedBits |= usedBits >> 8;
    usedBits |= usedBits >> 16;
    return ~num & usedBits;
}

对于2000000次迭代,上述情况需要130 ms,与之前的145 ms相比有利。

现在让我们尝试使用您的StringBuilder方法进行迭代:

public int findComplement(int num) {
    int ret = 0;
    for (int i = 1; i <= 20000; i++) {
        String s = Integer.toBinaryString(num);
        StringBuilder sb = new StringBuilder();
        for(char c : s.toCharArray()){
            sb.append(c == '1' ? 0 : 1);
        }
        ret |= Integer.parseInt(sb.toString(), 2);
    }
    return ret;
}

时间:785 ms(比特操作解决方案为37 ms)