1 题目
给定一个正整数 n,编写一个函数,获取一个正整数的二进制形式并返回其二进制表达式中 设置位 的个数(也被称为汉明重量)。
示例 1:
输入:n = 11
输出:3
解释:输入的二进制串 1011 中,共有 3 个设置位。
示例 2:
输入:n = 128
输出:1
解释:输入的二进制串 10000000 中,共有 1 个设置位。
示例 3:
输入:n = 2147483645
输出:30
解释:输入的二进制串 1111111111111111111111111111101 中,共有 30 个设置位。
提示:
1 <= n <= 231 - 1
2 代码实现
c++
cpp
class Solution {
public:
int hammingWeight(int n) {
int ret = 0 ;
for (int i = 0 ; i < 32 ; i++){
if (n & (1 << i )){
ret ++ ;
}
}
return ret ;
}
};
js
javascript
/**
* @param {number} n
* @return {number}
*/
var hammingWeight = function(n) {
let ret = 0 ;
for (let i = 0 ; i < 32 ; i++){
if (n & (1 << i )){
ret ++ ;
}
}
return ret ;
};
思考
我主要靠这题熟悉一下位运算的语法。
题解
第一步:理解题目和整体框架
这个函数的核心功能是:统计一个 32 位无符号整数的二进制表示中,数字 1 出现的次数(汉明重量)。我们先搭建最基础的类和函数框架:
cpp
// 定义一个解决方案类(LeetCode 标准写法)
class Solution {
public:
// 定义函数,返回值是int类型,参数n是要统计的32位整数
int hammingWeight(int n) {
// 核心逻辑会写在这里
}
};
class Solution:LeetCode 固定的类名,所有解题代码都放在这个类里。public:函数的访问权限,确保外部可以调用这个函数。int hammingWeight(int n):函数声明,hammingWeight是函数名,参数n是输入的整数,返回值是 1 的个数(整数)。
第二步:初始化计数器
接下来在函数内部定义一个变量,用来记录 1 的个数:
cpp
class Solution {
public:
int hammingWeight(int n) {
// 初始化计数器ret为0,ret是result的缩写,专门用来存1的个数
int ret = 0 ;
}
};
int ret = 0;:ret是计数器,初始值必须为 0(因为一开始还没统计到任何 1)。
第三步:循环遍历 32 位二进制位
因为题目明确是 32 位整数,所以我们需要检查每一位(从第 0 位到第 31 位):
cpp
class Solution {
public:
int hammingWeight(int n) {
int ret = 0 ;
// 循环32次,i从0到31,对应二进制的第0位(最低位)到第31位(最高位)
for (int i = 0 ; i < 32 ; i++){
// 每一位的检查逻辑写在这里
}
}
};
for (int i = 0 ; i < 32 ; i++):i = 0:从二进制最低位(最右边)开始检查。i < 32:因为是 32 位整数,必须检查完所有位(0~31 共 32 位)。i++:每次检查下一位。
第四步:检查当前位是否为 1
这是核心逻辑,用位运算 判断第 i 位是否为 1:
cpp
class Solution {
public:
int hammingWeight(int n) {
int ret = 0 ;
for (int i = 0 ; i < 32 ; i++){
// 关键位运算:判断n的第i位是否为1
if (n & (1 << i )){
ret ++ ; // 如果是1,计数器加1
}
}
}
};
这里拆解两个关键位运算:
1 << i:把数字 1 向左移动i位,生成一个 "只有第i位是 1,其余位都是 0" 的数。- 比如
i=0:1 << 0 = 1(二进制:000...0001)。 - 比如
i=1:1 << 1 = 2(二进制:000...0010)。 - 比如
i=3:1 << 3 = 8(二进制:000...1000)。
- 比如
n & (1 << i):按位与运算。只有当n的第i位是 1 时,结果才不为 0;否则结果为 0。- 举例:如果
n=5(二进制:000...0101),检查i=0:5 & 1 = 0101 & 0001 = 0001 ≠ 0→ 第 0 位是 1,ret加 1。 - 检查
i=1:5 & 2 = 0101 & 0010 = 0000 = 0→ 第 1 位是 0,不计数。 - 检查
i=2:5 & 4 = 0101 & 0100 = 0100 ≠ 0→ 第 2 位是 1,ret再加 1。
- 举例:如果
第五步:返回最终结果
循环结束后,ret 就是 1 的总个数,返回这个值:
cpp
class Solution {
public:
int hammingWeight(int n) {
int ret = 0 ;
for (int i = 0 ; i < 32 ; i++){
if (n & (1 << i )){
ret ++ ;
}
}
// 返回最终统计的1的个数
return ret ;
}
};
完整代码 + 测试示例
为了让你更直观理解,我们加一个 main 函数测试:
cpp
#include <iostream>
using namespace std;
class Solution {
public:
int hammingWeight(int n) {
int ret = 0 ;
for (int i = 0 ; i < 32 ; i++){
if (n & (1 << i )){
ret ++ ;
}
}
return ret ;
}
};
int main() {
Solution sol;
// 测试用例1:n=5(二进制0101),预期结果2
int n1 = 5;
cout << "n=5的二进制中1的个数:" << sol.hammingWeight(n1) << endl;
// 测试用例2:n=0(二进制全0),预期结果0
int n2 = 0;
cout << "n=0的二进制中1的个数:" << sol.hammingWeight(n2) << endl;
// 测试用例3:n=3(二进制0011),预期结果2
int n3 = 3;
cout << "n=3的二进制中1的个数:" << sol.hammingWeight(n3) << endl;
return 0;
}
运行结果:
n=5的二进制中1的个数:2
n=0的二进制中1的个数:0
n=3的二进制中1的个数:2
总结
- 核心思路 :遍历 32 位整数的每一位,用
1 << i定位第i位,再用&运算判断该位是否为 1,统计总数。 - 位运算关键 :
1 << i生成 "掩码",n & 掩码仅保留第i位的数值,非 0 则说明该位是 1。 - 边界处理:循环固定 32 次,确保覆盖 32 位整数的所有位(包括最高位的符号位)。
3 题目
给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。
示例 1 :
**输入:**nums = [2,2,1]
**输出:**1
示例 2 :
**输入:**nums = [4,1,2,1,2]
**输出:**4
示例 3 :
**输入:**nums = [1]
**输出:**1
提示:
1 <= nums.length <= 3 * 104-3 * 104 <= nums[i] <= 3 * 104- 除了某个元素只出现一次以外,其余每个元素均出现两次。
4 代码实现
c++
cpp
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ret = 0 ;
for (auto e : nums){
ret ^= e ;}
return ret ;
}
};
js
javascript
/**
* @param {number[]} nums
* @return {number}
*/
var singleNumber = function(nums) {
let ret = 0 ;
for (const e of nums){
ret ^= e ;
}
return ret ;
};
思考
泪目。25年7月用java提交过,现在毫无印象了,曾经还用java写算法hhh...
不过这题和位运算有什么关系?
啥意思,和0异或?异或得到的是啥,a和0异或得到的是a吧,a再和a异或就是0,所以说两轮异或得到0,一轮异或得到本身,也就是就出现过一次的数,妙啊,我看题解的我自己不会写的hhh。
5 小结
非常水的一节,也不能如此说,位运算主要是一个思路和语法,看了就知道的办法。不过我也是才做位运算的解法,还没做到难的。
坚持,加油!!!