Leetcode 793. Preimage Size of Factorial Zeroes Function
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
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(intK){ 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