【力扣每日一题】479. 最大回文数乘积

题目描述

给定一个整数 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次。这样理论上虽然两个方法时间复杂度看起来一样,但实际运行起来却是这种方法快很多。

你可能感兴趣的:(力扣每日一题,java,学习,力扣)