一、题目描述
给你两个整数 left
和 right
,表示区间 [left, right]
,返回此区间内所有数字 按位与 的结果(包含 left
、right
端点)。
示例 1:
输入:left = 5, right = 7 输出:4
示例 2:
输入:left = 0, right = 0 输出:0
示例 3:
输入:left = 1, right = 2147483647 输出:0
提示:
0 <= left <= right <= 2^31 - 1
二、解题思路
按位与操作会逐位比较两个整数的每一位,只有当两个数的对应位都是1时,结果的对应位才是1。因此,当给定一个区间[left, right]时,从最低位开始,我们首先比较这两个数的最低位是否相同,然后是次低位,依此类推。一旦发现某一位不同,那么这一位以及更高位的所有位在按位与操作后都将是0,因为区间内必然包含了这一位为0和为1的数。
所以,解题思路如下:
- 当
left
等于right
时,直接返回left
。 - 当
left
不等于right
时,我们不断将left
和right
右移,直到它们相等。每移动一位,相当于去掉最低位,直到两个数的所有不同位都被移除,剩下的就是它们的公共前缀。 - 由于我们在移位过程中已经将不同的位移除,最终
left
和right
相等的数就是我们要找的公共前缀,然后我们将这个数左移回原来的位置。
三、具体代码
class Solution {
public int rangeBitwiseAnd(int left, int right) {
// 记录原始的left值,用于计算需要左移的位数
int shift = 0;
// 当left不等于right时,不断右移,直到相等
while (left != right) {
left >>= 1;
right >>= 1;
shift++; // 记录右移的次数
}
// 将公共前缀左移回原来的位置
return left << shift;
}
}
四、时间复杂度和空间复杂度
1. 时间复杂度
- 在代码中,有一个
while
循环,该循环的执行次数取决于left
和right
的差值以及它们二进制表示中的最高不同位的位置。 - 在最坏的情况下,如果
left
和right
的最高位不同,则循环会一直执行直到最低位。假设left
和right
有n
位,那么循环最多执行n
次。 - 因此,时间复杂度是
O(n)
,其中n
是left
和right
二进制表示的位数。在32位整数的情况下,n
最大为32,所以时间复杂度也可以认为是O(1)
,因为n
是一个常数。
2. 空间复杂度
- 代码中使用了固定数量的变量:
left
、right
和shift
。这些变量只使用了常数级别的额外空间。 - 代码没有使用任何递归调用,也没有使用任何数据结构来存储额外的信息。
- 因此,空间复杂度是
O(1)
,表示算法使用了常数级别的额外空间。
综上所述,该算法的时间复杂度是O(1)
(或者更准确地说是O(n)
,其中n
是整数的位数),空间复杂度是O(1)
。
五、总结知识点
-
位操作符:
>>=
:右移赋值操作符,将变量右移指定的位数,并将结果赋给该变量。相当于先执行右移操作,然后赋值。<<
:左移操作符,将操作数左移指定的位数,并在右侧填充0。
-
循环结构:
while
循环:用于重复执行一段代码,直到指定的条件不再满足(即left
和right
相等)。
-
变量操作:
- 变量声明:
int shift = 0;
声明了一个整型变量shift
并初始化为0。 - 变量自增:
shift++;
用于在循环中记录右移的次数。
- 变量声明:
-
算法思想:
- 位运算技巧:通过不断地右移
left
和right
,来找到两个数的公共前缀,这是一种高效的算法技巧,适用于按位与操作的问题。
- 位运算技巧:通过不断地右移
-
函数定义:
public int rangeBitwiseAnd(int left, int right)
:定义了一个公共方法,接受两个整数参数,并返回一个整数结果。
以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。