考虑输入s(0)
和s(1)
的序列,以及所有s(n) = s(n-1) * s(n-2)
的{{1}}。我想在n >= 2
中找到尾随零的数量。我们可以假设以下内容:
s(n)
,n
和s(0)
作为输入s(1)
n <= 40
s(0) <= 20
以下是我的代码尝试。当s(1) <= 20
大于30(它运行很长时间)时,它不会运行。有没有其他方法可以计算尾随零的数量?
n
答案 0 :(得分:4)
您只需跟踪2和5的因子,而不是执行整个乘法。如果数字可以写为N = 2^a * 5^b * (factors other than 2 or 5)
,那么N
中的尾随零的数量是min(a, b)
。 (这是因为尾随零只是10的因子,需要一个2和一个5。)
请注意,乘法会将因子的指数加在一起。所以,如果你能写:
s(n-2) = 2^a * 5^b * (factors other than 2 or 5)
s(n-1) = 2^c * 5^d * (factors other than 2 or 5)
然后我们有:
s(n) = s(n-1) * s(n-2)
= 2^(a+c) * 5^(b+d) * (factors other than 2 or 5)
因此,我们可以将此问题视为两个Fibonacci sequences。您从s(0)
和s(1)
中的2和5开头,并以Fibonacci序列方式计算s(2), s(3), ..., s(n)
中的2和5的数量:
#2s in s(n) = (#2s in s(n-1)) + (#2s in s(n-2))
#5s in s(n) = (#5s in s(n-1)) + (#5s in s(n-2))
最后,尾随零的数量是min(#2s in s(n), #5s in s(n))
。
上述算法(如果使用循环或memoized递归实现)为O(n)
。您的尝试在n
中是指数级的,这就是为什么即使n = 30
也需要很长时间才能运行的原因。我并不打算抨击你的尝试,但理解这些错误是件好事 - 你的代码很慢,主要有两个原因:
首先,将非常大的整数乘以完全精度(正如您对BigInteger
所做的那样)非常慢,因为每次乘法的位数可以加倍。如果您只关心尾随零的数量,则无需完全精确。
其次,忽略乘法的成本,s
的递归实现仍然是指数时间,但它并非必须如此。请注意,您多次计算相同的值 - s(n-2)
是s(n)
和s(n-1)
分开计算的,但s(n-2)
的值明显相同。诀窍是通过记住先前计算的结果来memoize the recursion,以避免重新计算。或者,您可以使用循环计算Fibonacci类序列:
// Computes the n-th Fibonacci number in O(n) time
int[] fib = new int[n + 1];
fib[0] = 0;
fib[1] = 1;
for (int i = 2; i <= n; i++)
fib[i] = fib[i-1] + fib[i-2];
return fib[n];
这是一种比memoized递归更简单的方法,至少对于这个问题。
答案 1 :(得分:1)
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
int s0 = Integer.parseInt(br.readLine());
int s1 = Integer.parseInt(br.readLine());
int num21 = findNumberOf2s(s0);
int num22 = findNumberOf2s(s1);
int num51 = findNumberOf5s(s0);
int num52 = findNumberOf5s(s1);
int arr2[] = new int[n + 1];
arr2[0] = num21;
arr2[1] = num22;
for (int i = 2; i <= n; i++)
arr2[i] = arr2[i - 1] + arr2[i - 2];
int arr5[] = new int[n + 1];
arr5[0] = num51;
arr5[1] = num52;
for (int i = 2; i <= n; i++)
arr5[i] = arr5[i - 1] + arr5[i - 2];
System.out.println(Math.min(arr2[n], arr5[n]));
}
static int findNumberOf2s(int num) {
int num2 = 0;
while (num % 2 == 0) {
num = num / 2;
num2++;
}
return num2;
}
static int findNumberOf5s(int num) {
int num5 = 0;
while (num % 5 == 0) {
num = num / 5;
num5++;
}
return num5;
}