阶乘中最低位0的个数&二进制表示中最低位1的位置

本文介绍了如何计算一个整数的阶乘末尾有多少个0,以及如何找到阶乘的二进制表示中最低位1的位置。通过质因数分解和迭代计算的方法,我们可以高效解决这些问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/***************************问题描述************************** 
1. 给定一个整数N,那么N的阶乘N!末尾有多少个0? 
2. 求N!的二进制表示中最低位1的位置 
*************************************************************/  
  
  
  
/************************问题1思路**************************** 
N!=K*power(10,M),K不能被10整除,则N!末尾有M个0。对N!进行质因数 
分解,有N!=power(2,X)*power(3,Y)*power(5,Z)*...,由于10=2×5, 
因此N!有多少个0显然只与X,Z有关,易得M=min(X,Z),因为2出现的频率 
大于等于5,所以M=Z,即问题化简为求N!中5的个数 
*************************************************************/  
  
/***********************解法1:直接暴力********************** 
遍历i=1,2,...,N中每个因子包含5的个数,然后相加 
************************************************************/  
  
int findNumof5v1(int N){  
    int count=0;  
    for(int i=1;i<=N;i++){  
        int j=i;  
        while(j%5==0){  
            count++;  
            j/=5;  
        }  
    }  
    return count;  
}  
  
/**********************解法2:***************************** 
Z=小于N的数中是5的倍数的个数+25的倍数的个数+125的倍数的个数... 
即Z=[N/5]+[N/(5*5)]+[N/(5*5*5)]+... 
***********************************************************/  
int findNumof5v2(int N){  
    int count=0;  
    while(N){  
        count += N/5 ;  
        N /=5 ;  
    }  
    return count;  
}  
  
/*************************问题2思路*************************** 
跟问题1类似,可以先求出N!中2的个数(因为每存在一个2,则在数的 
最低位多1个0)。因此求1的最低位的位置即为N!中2的个数+1; 
*************************************************************/  
int lowestOnePos(int N){  
    int count=0;  
    while(N){  
        count += N/2 ;  
        N /= 2;  
    }  
    return count + 1 ;  

}  


 求一个数的二进制表示中1的个数

/**************问题描述************ 
求二进制数中1的个数 
**********************************/  
  
#include<iostream>  
using namespace std;  
  
/****************解法一:直接除2******************* 
对num除以2,余数为1则result加1,时间复杂度为O(logv) 
v为num的二进制位数 
**************************************************/  
int Count1(int num){  
    int result=0;  
    while(num){  
        if(num %2 ==1){  
            result++;  
        }  
        num /=2;  
    }  
    return result;  
}  
  
/******************解法二:使用位操作************* 
对num使用位运算,将num与0x01做位与,为1则result加1 
时间复杂度为O(logv),v为num的二进制位数 
*************************************************/  
int Count2(int num){  
    int result=0;  
    while(num){  
        result += num&1 ;  
        num >>= 1;  
    }  
    return result;  
}  
  
/***************解法三:光考虑1的个数************ 
例如对num=15=1111, 
num=num&(num-1)=1111&1110=1110,result=1; 
num=num&(num-1)=1110&1101=1100,result=2; 
num=num&(num-1)=1100&1011=1000,result=3; 
num=num&(num-1)=1000&0111=0000,result=4; 
时间复杂度O(M),M为num的位数 
*************************************************/  
int Count3(int num){  
    int result=0;  
    while(num){  
        num &= (num-1);  
        result ++;  
    }  
    return result;  
}  
  
/***************解法四:时空折中***************** 
假设知道输入的num为几位数的话,可以预先存好每个数 
有多少个1,然后到时候直接查询即可。这样需要多申请 
2^n那么大的数组来保存,但是时间复杂度为O(1) 
*************************************************/  
#define MAIN  
#ifdef MAIN  
int main(){  
    int num=16;  
    int result=Count1(num);  
    cout<<"Result1: "<<result<<endl;  
    cout<<"Result2: "<<Count2(num)<<endl;  
    cout<<"Result3: "<<Count3(num)<<endl;  
    system("PAUSE");  
    return 0;  
}  
#endif  


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值