1532.在区间范围内统计奇数数目
给你两个非负整数 low
和 high
。请你返回 low
和 high
之间(包括二者)奇数的数目。
示例 1:
输入:low = 3, high = 7 输出:3 解释:3 到 7 之间奇数数字为 [3,5,7] 。
示例 2:
输入:low = 8, high = 10 输出:1 解释:8 到 10 之间奇数数字为 [9] 。
思路:
用[1,high]区间奇数个数[1,low-1]区间奇数个数。
[1,n]区间奇数个数=(n+1)/2.如1~2为1;1~7为4,所以3~7为3.
class Solution {public int countOdds(int low, int high) {return((high+1)>>1)-(low>>1);}
}
最终公式:
((high + 1) >> 1) - (low >> 1)
这个式子意思是:
从 1 到 high 有多少个奇数 ➖ 从 1 到 (low - 1) 有多少个奇数。
🧩 位运算 >> 1
是什么?
👉 x >> 1
等于 x ÷ 2
(向下取整)
这是右移一位,等价于整数除以 2:
-
7 >> 1
=3
(7 ÷ 2 = 3.5 向下取整为 3) -
8 >> 1
=4
⚠️ 注意:这是 整数除法,不会有小数。
🧮 举例解释公式:
我们来看例子:
比如 low = 3, high = 7
,区间是 [3, 4, 5, 6, 7]
里面有奇数:3, 5, 7 → 总共 3 个奇数
来看公式计算:
((high + 1) >> 1) - (low >> 1) = ((7 + 1) >> 1) - (3 >> 1) = (8 >> 1) - (1) = 4 - 1 = 3 ✅
再看一个例子:
low = 4, high = 10
,区间 [4,5,6,7,8,9,10]
奇数有:5, 7, 9 → 3 个奇数
用公式:
((10 + 1) >> 1) - (4 >> 1) = (11 >> 1) - (2) = 5 - 2 = 3 ✅
✅ 为什么不直接 (high - low + 1) / 2 + ...
?
这种写法是更快且更简洁的数学解法:
-
它利用了从 1 到 x 之间奇数个数就是
(x + 1) / 2
-
而
(x + 1) >> 1
是等效于(x + 1) / 2
的写法,但在位运算层面更快
🌟 Java 中常见的位运算符
运算符 | 名称 | 作用 |
---|---|---|
& | 按位与 | 同为1结果才是1 |
` | ` | 按位或 |
^ | 按位异或 | 相同为0,不同为1 |
~ | 按位取反 | 0变1,1变0 |
<< | 左移 | 向左移动位数,相当于乘2 |
>> | 右移 | 向右移动位数,相当于除2(符号位保留) |
>>> | 无符号右移 | 不保留符号位(正负都补0) |
💡 常见用途举例:
1️⃣ 判断奇偶数(%2 的替代)
if ((n & 1) == 1) {
System.out.println("n 是奇数");
}
else {
System.out.println("n 是偶数");
}
-
原理:奇数的二进制最后一位一定是
1
。
2️⃣ 交换两个数(不使用临时变量)
a = a ^ b; b = a ^ b; a = a ^ b;
3️⃣ 检查某一位是否为1(掩码)
int n = 10; // 二进制:1010 int k = 1; // 想检查第2位(从右边开始数,从0开始) boolean isBitSet = (n & (1 << k)) != 0;
-
(1 << k)
相当于“掩码”——只关心第 k 位是否为1
4️⃣ 设置 / 清除 / 取反 某一位
-
设置第
k
位为1
:n = n | (1 << k);
-
清除第
k
位为0
:n = n & ~(1 << k);
-
翻转第
k
位:n = n ^ (1 << k);
5️⃣ 快速乘除 2 的幂
n << 1 // 相当于 n * 2 n >> 1 // 相当于 n / 2(向下取整) n << k // 相当于 n * 2^k
6️⃣ 判断两个整数是否符号相同
boolean sameSign = (a ^ b) >= 0;
-
如果符号相同,a^b 的符号位是 0
7️⃣ 只出现一次的数字(LeetCode 常考)
给定一个数组,其他数字都出现两次,只有一个数字出现一次,找出它。
public int singleNumber(int[] nums) { int result = 0; for (int num : nums) { result ^= num; } return result; }
-
利用异或:
a ^ a = 0
,0 ^ b = b
8️⃣ 判断一个数是不是 2 的幂(只能有一个1)
boolean isPowerOfTwo = (n > 0) && ((n & (n - 1)) == 0);
🔚 总结一句口诀:
“与可清零,或可置一,异或翻转最神奇;移位快算乘除法,掩码专攻某一位。”