问题内容
基本描述
我们称一个数字字符串是好数字当它满足:(下标从 0 开始偶数下标处的数字为偶数,且奇数下标处的数字为质数(2,3,5 或 7)。
比方说,“2582” 是好数字,因为偶数下标处的数字(2 和 8)是偶数且奇数下标处的数字(5 和 2)为质数。但 “3245” 不是 好数字,因为 3 在偶数下标处但不是偶数。
给你一个整数n,请你返回长度为 n 且为好数字的数字字符串总数 。由于答案可能会很大,请你将它对
1
0
2
+
7
10^2+7
102+7 取余后返回 。
一个 数字字符串 是每一位都由 0 到 9 组成的字符串,且可能包含前导 0 。
实例
输入:n = 1
输出:5
输入:n = 4
输出:400
算法求解:分治+递归
思路
对于偶数下标处的数字,它可以为
0
,
2
,
4
,
6
,
8
0,2,4,6,8
0,2,4,6,8共计5种,而长度为
n
n
n的数字字符串有
(
n
+
1
)
/
2
(n+1)/2
(n+1)/2个偶数下标;对于奇数下标处的数字,它可以为
2
,
3
,
5
,
7
2,3,5,7
2,3,5,7共计5种,而长度为
n
n
n的数字字符串有
n
/
2
n/2
n/2个奇数下标。因此长度为
n
n
n的数字,好数字的总数为
5
(
n
+
1
)
/
2
×
4
n
/
2
5^{(n+1)/2} \times 4^{n/2}
5(n+1)/2×4n/2
由于
5
(
n
+
1
)
/
2
5^{(n+1)/2}
5(n+1)/2 较大,为了提升速度,可以采用分治+回溯的方式来求解。具体如下:
当我们要计算
x
n
x^n
xn时,可以先递归地计算
y
=
x
n
/
2
y=x^{n/2}
y=xn/2;
如果
n
n
n为偶数,
x
n
=
y
2
x^n=y^2
xn=y2;如果
n
n
n为奇数,
x
n
=
x
×
y
2
x^n=x\times y^2
xn=x×y2。
递归的边界为
n
=
0
n=0
n=0,此时
y
=
0
y=0
y=0。
代码
以下代码需要特别注意的是,需要使用long型,而不是int型,否则当n>=15时,结果就会因为溢出而报错。
public int countGoodNumbers(long n) {
long mod = (long) 1e9 + 7;
long ans = f(5,(n+1)/2, mod)*f(4,n/2, mod) % mod;
return (int) ans;
}
public static long f(int x, long n, long mod){
if (n == 0){
return 1;
}
long y = f(x, n/2, mod);
if (n%2==0){
return y*y % mod;
}else {
return y*y*x % mod;
}
}
复杂度分析
时间复杂度:
O
(
l
o
g
n
)
O(log\ n)
O(log n),即递归的层数。
空间复杂度:
O
(
l
o
g
n
)
O(log\ n)
O(log n),即递归的层数。这是由于递归的函数调用会使用栈空间。