C/C++解OJ题--比特位计数(动态规划方式VS普通迭代方式)


   动态规划VS 普通迭代


原题如下:
在这里插入图片描述
  给你一个整数 n ,对于 0 <= i <= n 中的每个 i ,计算其二进制表示中 1 的个数 ,返回一个长度为 n + 1 的数组 ans 作为答案。

审题:
  题目所表达的意思是给我们一个整数n,例如给我们的整数是5。那么我们要计算0、1、2、3、4、5这几个数所对应转换为二进制后其中1的数目,最后以数组的形式返回这些结果,如下:
在这里插入图片描述
  解读:下标为3的数组元素:3 转换为二进制后为(11)有2个1,所以下标3所对应的数据是2。


思路:
思路一:普通迭代方式
  对于本题,通俗的说就是我们申请一个数组大小为 n +1的数组,计算每个下标对应的二进制中1的个数,将这个总数记录到该下标位置中即可。既然如此,那么我们就遍历计算就可以。
  但是这种方式没有利用到已经计算的记录所以效率比较低,不过还是实现一下.

思路二:动态规划
  动态规划的核心思想是:利用已知记录完成对未知记录的计算。
  所以更好的方式是使用动态规划,有关动态规划的思想及解题步骤在往期的一道OJ题文章中有详细分享,有兴趣的可以了解一下。
   动态规划
  对于动态规划我们没有必要去深究原理,要想理解动态规划,更多的还是去解题找感觉。
  下面根据动态规划的思想与解题步骤我们来进行解读。
解题步骤:
1.定义dp数组所表示的含义
  给我们一个整数 n ,题目要求我们返回一个数组。而数组元素所表示的是0<=i(下标)<=n所对应二进制中1的数目。
  因此定义dp数组为:下标 i 所对应的二进制中 1 的个数为 dp[i]

2.确定递推公式
  在此之前补充点知识:
  先来看十进制,我们在十进制的世界中将一个整数扩大十倍是不是在低位补一个零,或者说将该整数左移一位。那么同样在二进制的世界中,将一个数扩大两倍,也就是在低位补一个0,或者说左移动一位。它们是相通的
  再来看一点,在十进制的世界中有2位数,3位数……同样在二进制的世界中 0~4 表示为:00、01、10…… 5~8 表示为:101、110……也是类似的,理解这两点是确定递推公式的关键
  最后一步:假设要我们求解n,现在我们已经知道了下标为n-1及其之前数的二进制数中 1 的数目。那么dp[n]的值取决于什么?
  基于上面所分享的补充知识,dp[n]的值要分偶数与奇数来考虑,所以存在下面的递推公式。
  如果n是偶数dp[n]=dp[n/2]
  如果n是奇数dp[n]=dp[n-1]+1

3.确定初始条件及边界情况
  根据递推公式当n=1的时候是不能由递推公式分解得出,因为数组下标无负数,当 n =0也不能由递推公式得出所以要直观的给出dp[1]与dp[0]的结果
  边界情况自然是数组不能越界访问。

4.遍历顺序(计算顺序)
  根据递推公式要求解等式左边的必须知道等式右边的(n>n-1)所以要从小到大进行遍历。


代码实现:
普通迭代:

//C实现
int oneSum(int number)
{
    int sum=0;//标记1的总数目
    int i=0;//标记余数
    while(number>0)
    {
        //先模运算取余,再做除法
        i=number%2;   //先模运算取余
        if(i==1)sum++;//如果余数为1,则将sum++
        number/=2;//再做除法
    }
    return sum;//返回最后的总数
}

int* countBits(int n, int* returnSize){
    int*result=(int*)malloc(sizeof(int)*(n+1));//将结果放到数组中
    *returnSize=(n+1);
    for(int i=0;i<=n;i++)//计算每个下标所对应二进制数中1的总数目
    {
        int sum=oneSum(i);//调用计算的接口函数
        result[i]=sum;
    }
    return result;
}

动态规划:

//C++实现
class Solution {
public:
    vector<int> countBits(int n) {
        vector<int>dp(n+1);//申请一个dp数组
        dp[0]=0;
        if(n==0)return dp;//防止越界
        dp[1]=1;//不能有递推公式求解的要直观的给出答案
        for(int i=2;i<=n;i++)
        {
            if(i%2==0)//如果是偶数
            {
                dp[i]=dp[i/2];//低位补0,所以与i/2的位置相同
            }
            else//是奇数
            {
                dp[i]=dp[i-1]+1;//在前一位的基础上再低位补1,所以比前一个多1
            }
        }
        return dp;
    }
};

序:
  到现在为止每次碰见动态规划类型的题目都还会让我思考很长时间。动态规划的思想和基本操作不难,但是总是比较棘手,所以也就只有不断加强练习。
  这次的解题分享就到这里。


  我是老胡,感谢阅读!!!❤️ ❤️

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值