《编程之美》2.2 不要被阶乘吓倒

题目:

1. 给定一个整数N,nameN的阶乘N!结尾有多少个0呢?

2.求N!的二进制表示中最低位1的位置

 

 1 #include <iostream>
 2 
 3 
 4 // 遍历1~N,找到每一个5的倍数包含5这个因数的个数
 5 // 比如 N=34,我们会找到
 6 //      1. 数字5包含1个因数5(5=1*5), 
 7 //      2. 数字10包含1个因数5(10=2*5)
 8 //      3. 数字15包含1个因数5(15=3*5), 
 9 //      4. 数字20包含1个因数5(20=4*5), 
10 //      5. 数字25包含2个因数5(25=5*5), 
11 //      5. 数字30包含1个因数5(30=2*3*5), 
12 //      一共找到1+1+1+1+2+1=7个5
13 int count0_way1( int N ) 
14 {
15     int count = 0; 
16     for ( int i = 1; i <= N; i++ ) {
17         int j = i; 
18         while ( j % 5 == 0 ) {
19             count++; 
20             j /= 5; 
21         }
22     }
23     return count; 
24 }
25 
26 // 我们也可以直接在1~N中找到包含因数5的数的个数,
27 // 比如 N=34的数字中,
28 //      1. 包含1个因数5的数字有5,10,15,20,25,30,共6个(即34/5的结果)
29 //      2. 包含2个因数5的数字(即25)有25, 共1个,即34/25的结果,
30 //      3. 包含3个因数5的数字(即125)有0个,即34/125的结果,
31 //      4. .....
32 //      一共找到34/5 + 34/25 = 6+1=7 个
33 int count0_way2( int N )
34 {
35     int count = 0; 
36     while ( N ) {
37         count += N / 5; 
38         N = N / 5; 
39     }
40     return count; 
41 }
42 
43 
44 // 求N!结果中最低位置1的位置,等同于求N!的2的质因数的个数
45 // 我们可以观察到,
46 //     1. 任何奇数的二进制表示中,最后一位都是1
47 //     2. 任意多个奇数相乘的结果依然是奇数,也就是说,奇数相乘,其结果的最后一位1总是在最低位上
48 //     3. 任意一个数,都可以分解为质因数相乘,在所有的质数中,只有2是偶数,其余的都是奇数
49 //     4. 一个数乘以2,相当于其二进制表示左移一位, 即最低位的1的位置向左移动一位
50 //     5. 因此,我们把算式 N! = N*(N-1)*(N-2)*(N-3)....*1 分解质因式,其所有的因子中,只会存在2和奇数(因为质数中只有2是偶数)
51 //        根据2,奇数的乘积还是奇数,只有因数2才会改变最低位1的位置,每乘一次2(也即出现一个因子2)就会使得1的位置左移一次
52 //     得到我们的结论:求N!结果中最低位置1的位置,等同于求N!的2的质因数的个数, 
53 //     求N!中质因数2的个数的方法可以参考Question1的方法2, 
54 int OnePosition_way1(int N ) 
55 {
56     int count = 0; 
57     while ( N ) {
58         count += N / 2;
59         N = N >> 1; 
60     }
61     return count + 1; 
62 }
63 
64 
65 int main( int argc, char** argv )
66 {
67     // Question1: 求N!的结果中,结尾0的个数。 
68     // 求一个乘法算式结果的结尾0的个数,等同于求乘法算式中因子10的个数,而10=2*5,且在自然数的因子中,因子2的个数大于因子5的个数,
69     // 因此,求这个算式结果的结尾0的个数,等同于求这个算式中因子5的个数
70     int N = 34; 
71     std::cout << " count 0 in " << N << std::endl; 
72     std::cout << " way1: " << count0_way1( N ) << std::endl; 
73     std::cout << " way2: " << count0_way2( N ) << std::endl; 
74     std::cout << " DONE " << std::endl; 
75 
76 
77     // Question2: 求N!结果的二进制表示中,最低位1的位置,比如 N=3, N!=3*2*1=6=0b(110), 其结尾最低位1的位置是2.
78     std::cout << " the positon of lowest 1 : in " << N << std::endl; 
79     std::cout << " way1: " << OnePosition_way1( N ) << std::endl; 
80     //std::cout << " way2: " << 1position_way2( N ) << std::endl; 
81     std::cout << " DONE " << std::endl; 
82 
83     return 0; 
84 }

 

posted @ 2022-05-11 15:19  或多或少jlhou  阅读(101)  评论(0编辑  收藏  举报