题目描述
给定一个整数 n ,返回 可表示为两个 n 位整数乘积的 最大回文整数 。因为答案可能非常大,所以返回它对 1337
取余 。
示例 1:
输入:n = 2
输出:987
解释:99 x 91 = 9009, 9009 % 1337 = 987
示例 2:
输入: n = 1
输出: 9
提示:
1 <= n <= 8
啊,是一个困难题,但看到n的取值范围,这题又变简单了~
直接打表
class Solution {
public int largestPalindrome(int n) {
int[] ans = {9,987,123,597,677,1218,877,475};
return ans[n-1];
}
}
正规做法是什么呢?是枚举,当然不是一一枚举n位数判断乘积是否是回文数,那样肯定超时;而是从大到小枚举回文数,判断能不能变成两个n位数的乘积。
我们只需要从10n-1 枚举出回文数的左半部分,然后得到回文数p,再从10n-1枚举x,如果p能整除x且x和p/x均为n位整数,则返回答案p%1337。过程中x只需要枚举到p1/2即可。
另外,n为1时,需要特殊判断,返回9;
class Solution {
public int largestPalindrome(int n) {
if(n==1) return 9;
int ans = 0;
int upper = (int)Math.pow(10,n)-1;//枚举开始的数
for(int left=upper;ans==0;left--){//枚举回文数左半部分
//构建完整的回文数
long p = left;
for(long x=left;x>0;x/=10)
p = p*10 + x%10;
//枚举x
for(long x=upper;x*x>=p;x--){
if(p%x==0){
ans = (int)(p%1337);
break;
}
}
}
return ans;
}
}
时间复杂度:O(102n),枚举left和x的时间复杂度均为O(10n),但实际我们不需要枚举很多,所以实际上的时间复杂度远低于O(102n)。
空间复杂度:O(1),只需要常数空间去存储变量。
枚举通常有超时的风险,想要控制时间,主要得看从哪个方面进行枚举比较方便。
1.这里如果从n位数开始从大到小枚举,像这样:
//若n=5,upper=99999,downer=10000
int upper = (int)Math.pow(10,n)-1;
int downer = (int)Math.pow(10,n-1);
for (int x=upper;x>downer;x--){
for(int y=upper;y>downer;y--){
......
}
}
因为你虽然知道x,y要尽量大,却不知道到底x,y具体在什么范围,所以只能全都遍历一遍,那复杂度就可能真的至少要达到O(10n)左右了。
2.而从回文数开始判断,我们只看回文数p能不能被x整除。合适的p其实不会太小,所以无需遍历10n次,而x至多从upper到p1/2,也无需遍历10n次。这样理论上虽然两个方法时间复杂度看起来一样,但实际运行起来却是这种方法快很多。