Leetcode 144 位1的个数 | 只出现一次的数字

1 题目

191. 位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. 1 << i:把数字 1 向左移动 i 位,生成一个 "只有第 i 位是 1,其余位都是 0" 的数。
    • 比如 i=01 << 0 = 1(二进制:000...0001)。
    • 比如 i=11 << 1 = 2(二进制:000...0010)。
    • 比如 i=31 << 3 = 8(二进制:000...1000)。
  2. n & (1 << i):按位与运算。只有当 n 的第 i 位是 1 时,结果才不为 0;否则结果为 0。
    • 举例:如果 n=5(二进制:000...0101),检查 i=05 & 1 = 0101 & 0001 = 0001 ≠ 0 → 第 0 位是 1,ret 加 1。
    • 检查 i=15 & 2 = 0101 & 0010 = 0000 = 0 → 第 1 位是 0,不计数。
    • 检查 i=25 & 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

总结

  1. 核心思路 :遍历 32 位整数的每一位,用 1 << i 定位第 i 位,再用 & 运算判断该位是否为 1,统计总数。
  2. 位运算关键1 << i 生成 "掩码",n & 掩码 仅保留第 i 位的数值,非 0 则说明该位是 1。
  3. 边界处理:循环固定 32 次,确保覆盖 32 位整数的所有位(包括最高位的符号位)。

3 题目

136. 只出现一次的数字

给你一个 非空 整数数组 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 小结

非常水的一节,也不能如此说,位运算主要是一个思路和语法,看了就知道的办法。不过我也是才做位运算的解法,还没做到难的。

坚持,加油!!!

相关推荐
暮冬-  Gentle°2 小时前
C++中的工厂模式实战
开发语言·c++·算法
Lisssaa2 小时前
打卡第二十二天
c++·算法·图论
pu_taoc2 小时前
理解 lock_guard, unique_lock 与 shared_lock 的设计哲学与应用场景
开发语言·c++·算法
red_redemption2 小时前
自由学习记录(144)
学习
小刘不想改BUG2 小时前
LeetCode 138.随机链表的复制 Java
java·leetcode·链表·hash table
XW01059992 小时前
6-函数-1 使用函数求特殊a串数列和
数据结构·python·算法
myloveasuka2 小时前
红黑树、红黑规则、添加节点处理方案
开发语言·算法
沉鱼.442 小时前
枚举问题集
java·数据结构·算法
2301_810160952 小时前
C++中的访问者模式高级应用
开发语言·c++·算法