【LeetCode】338、比特位计数

一、题目信息

cpp 复制代码
给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。
不要使用内置函数来解决(例如,C++ 中的 __builtin_popcount)。

示例 1:
输入:n = 2
输出:[0,1,1]
解释:
0 --> 0
1 --> 1
2 --> 10

示例 2:
输入:n = 5
输出:[0,1,1,2,1,2]
解释:
0 --> 0
1 --> 1
2 --> 10
3 --> 11
4 --> 100
5 --> 101

提示:
0 <= n <= 105
进阶:
很容易就能实现时间复杂度为 O(n log n) 的解决方案,你可以在线性时间复杂度 O(n) 内用一趟扫描解决此问题吗?

二、题解1:朴素解法

1、解题思路:二进制转换法

  • 题目要求计算一个十进制整数的二进制形式中1的数字个数

  • 使用for循环遍历每个数字,然后对遍历到的每个数字进行二进制转换,将十进制转换成对应二进制

  • 在转换的过程中,记录数字1个个数

2、图解

3、代码实现

cpp 复制代码
vector<int> countBits(int n)
{
    vector<int> res(n + 1, 0);

    string binaryStr = ""; // 数字i对应的二进制结果值

    for (int i = 0; i <= n; i++)
    {
        int num = i;
        binaryStr = "";
        while (num != 0)
        {
            // 十进制数字num转换成二进制
            int remainder = num % 2; // 取余数
            int business = num / 2;  // 商

            if (remainder == 1)
            {
                res[i]++;
            }
            num = business;
            binaryStr = to_string(remainder) + binaryStr;
        }
        std::cout << i << " -- " << binaryStr << std::endl;
    }

    return res;
}

4、时间复杂度

  • NlogN ,因为遍历需要计算n次,对每个数字i进行二进制转换需要logN次,结果相乘

三、题解2:位运算&解法

1、解题思路

  • 通过位运算符&,求i&(i-1)的结果值,会将数字i的二进制最右侧的数字1消除掉

  • 这样不断重复这个操作,将所有二进制形式的1消除掉,记录循环的次数就是对应二进制中1的个数

2、图解

3、代码实现

cpp 复制代码
vector<int> countBits(int n)
{
    vector<int> res(n + 1, 0);

    for (int i = 0; i <= n; i++)
    {
        int num = i;
        while (num != 0)
        {
            num = num & (num - 1);
            res[i]++;
        }
    }

    return res;
}

4、时间复杂度

  • NlogN ,每个数字i的二进制1个数为logn的个数,要找出所有1的个数

四、题解3:位移解法

1、解题思路

  • 十进制数字i,要求他的一半大小,只需要将他的二进制形式往右边位移一位

  • 如果这个数字i是偶数的话,那他二进制最右侧的数字是0,i的二进制中1的数字个数,和i/2的二进制中1的数字个数相同。

  • 如果数字i是奇数的话, 对应二进制最右侧的数字肯定是1,那i的二进制往右位移一位后,得到i/2的二进制1的个数比i的二进制1的个数少1.

  • 可以通过这个规律来求解i的二进制中1的个数的值。

2、图解

3、代码实现

cpp 复制代码
vector<int> countBits(int n)
{
    vector<int> res(n + 1, 0);

    for (int i = 1; i <= n; i++)
    {
        res[i] = res[i / 2] + (i & 1);
    }

    return res;
}

4、时间复杂度

  • O(N),动态规划解法,首先要找数字i与i/2的规律,再根据他们的关系来一步步求解
相关推荐
木子算法1 小时前
不是重心也不是中点:费马—韦伯点、它的最优性条件与迭代求解
人工智能·算法·目标跟踪
程序员AlbertTu2 小时前
# Mantissa 使用教程 — Python 版与 C++ 版
c++·python·数值运算
Lazionr2 小时前
多态:从多种形态到运行时绑定
开发语言·c++
tryxr2 小时前
矩阵的几种基础变换
java·数据结构·算法·矩阵
mmmmath_32 小时前
LeetCode.028.找出字符串中第一个匹配项的
数据结构·算法·leetcode
别动我齐刘海2 小时前
ROS2 Jazzy + C++ 实战路线——ros2_control
c++·人工智能·python·opencv·机器学习·机器人·github
Selvaggia2 小时前
DMD(Distribution Matching Distillation,分布匹配蒸馏)
算法
Navigator_Z3 小时前
LeetCode //C - 1255. Maximum Score Words Formed by Letters
c语言·算法·leetcode
All for pursuit.3 小时前
【栈-4】739.每日温度
数据结构·c++·算法·leetcode