1. 程式人生 > >Leetcode 793. Preimage Size of Factorial Zeroes Function

Leetcode 793. Preimage Size of Factorial Zeroes Function

發現 要求 minimal 溢出 integer 解答 discuss 好的 ref

Problem:

Let f(x) be the number of zeroes at the end of x!. (Recall that x! = 1 * 2 * 3 * ... * x, and by convention, 0! = 1.)

For example, f(3) = 0 because 3! = 6 has no zeroes at the end, while f(11) = 2 because 11! = 39916800 has 2 zeroes at the end. Given K, find how many non-negative integers x

have the property that f(x) = K.

Example 1:
Input: K = 0
Output: 5
Explanation: 0!, 1!, 2!, 3!, and 4! end with K = 0 zeroes.

Example 2:
Input: K = 5
Output: 0
Explanation: There is no x such that x! ends in K = 5 zeroes.

Note:

  • K will be an integer in the range [0, 10^9].

Solution:

  這道題很有意思,要求我們找出所有數字n的個數,使得n!結尾有K個0。看到這個問題,想到以前的非常規二分搜索方法,在結果可能的範圍內查找滿足條件的最小值,這裏使用了Leetcode 172 Factorial Trailing Zeroes中的函數,然後在getMinimal函數中找到結尾有K個0的最小值,然後getMinimal(K+1)-getMinimal(K)

即可。

 1 class Solution {
 2 public:
 3     int trailingZeroes(int n) {
 4         int count_five = 0;  
 5         while(n > 0){  
 6             int k = n/5;  
 7             count_five += k;  
 8             n = k;  
 9         }  
10         return count_five;    
11     }
12     int getMinimal(int
K){ 13 int start = 0; 14 int end = INT_MAX; 15 while(start < end){ 16 int pivot = start+(end-start)/2; 17 if(trailingZeroes(pivot) < K) 18 start = pivot+1; 19 else 20 end = pivot; 21 } 22 return start; 23 } 24 int preimageSizeFZF(int K) { 25 return getMinimal(K+1)-getMinimal(K); 26 } 27 };

  然而這個算法卻不能通過最後一個測試10^9,原因是結尾有10^9個0的最小值n!,其n已經大於INT_MAX了,當然我們可以修改二分搜索範圍,使用int64_t類型即可AC並擊敗100.00%的提交,代碼如下

 1 class Solution {
 2 public:
 3     int64_t trailingZeroes(int64_t n) {
 4         int64_t count_five = 0;  
 5         while(n > 0){  
 6             int64_t k = n/5;  
 7             count_five += k;  
 8             n = k;  
 9         }  
10         return count_five;    
11     }
12     int64_t getMinimal(int64_t K){
13         int64_t start = 0;
14         int64_t end = (int64_t)2*INT_MAX;
15         while(start < end){
16             int64_t pivot = start+(end-start)/2;
17             if(trailingZeroes(pivot) < K)
18                 start = pivot+1;
19             else
20                 end = pivot;
21         }
22         return start;
23     }
24     int64_t preimageSizeFZF(int64_t K) {25         return getMinimal(K+1)-getMinimal(K);
26     }
27 };

  但是這樣做未免有投機取巧之嫌,因此我們采用另一種更好的方法,不過這種方法需要一定的觀察,我們發現,如果存在n使得n!末尾有K個0,那麽答案必然是5(比如K為1,那麽5,6,7,8,9均可,當n為10則會引入新的質因數5導致末尾有2個0),如果根本不存在這樣的n,那麽結果是0,因此答案只有0和5兩種可能。現在問題在於如果存在這樣的n,n會在什麽範圍內。n的下限必然為K(觀察可知末尾0的數量必然小於等於n),n的上限可以是5*(K+1)(觀察可知末尾有K個0的最大值必然小於等於5(K+1),可以用上面的getMinimal驗證),因此在這個範圍內二分搜索即可,就K=1為例,一旦搜索到5,6,7,8,9中的任意值都可以直接返回,搜索結束還沒有找到滿足條件的值則返回0.註意即使是這種方法仍然無法避免整形溢出問題,但明顯比上面那種無腦二分的方法合理。

  ps:這道題還可以用直接找規律的方法解答,但作為一道算法題,不建議用這種純觀察的方法做。解答在這裏

Code:

 1 class Solution {
 2 public:
 3     int trailingZeroes(int64_t n) {
 4         int64_t count_five = 0;  
 5         while(n > 0){  
 6             int64_t k = n/5;  
 7             count_five += k;  
 8             n = k;  
 9         }  
10         return count_five;    
11     }
12     int preimageSizeFZF(int K) {
13         int64_t start = K;
14         int64_t end = (int64_t)5*(K+1);
15         while (start < end) {
16             int64_t pivot = start+(end-start)/2;
17             int count = trailingZeroes(pivot);
18             if (count == K) 
19                 return 5;
20             else if (count < K) 
21                 start = pivot + 1;
22             else 
23                 end = pivot;
24         }
25         return 0;
26     }
27 };

Leetcode 793. Preimage Size of Factorial Zeroes Function