持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第1天,点击查看活动详情
现在前端很多岗位面试需要有一定的算法基础,或者说经常刷算法的会优先考虑。
因此每天刷刷LeetCode非常有必要
在这之前我也刷过一些算法题,也希望以后也坚持刷,跟某掘友一样,我也想刷穿 LeetCode
一、题目描述
给定一个整数 n ,返回 可表示为两个 n 位整数乘积的 最大回文整数 。因为答案可能非常大,所以返回它对 1337 取余 。
示例 1:
输入:n = 2
输出:987
解释:99 x 91 = 9009, 9009 % 1337 = 987
示例 2:
输入: n = 1
输出: 9
提示:
1 <= n <= 8
来源:力扣(LeetCode) 链接:leetcode.cn/problems/la… 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
二、思路分析
核心思路:当n>1时,两个位数为n的数的乘积一定是位数为2n的数
这样的话,我们在对n=1特殊处理之后,就可以对剩余的位数为2n的数分成左右两部分处理了。
当然,题目要求我们找到最大的回文数,那么,我们需要从n位数中最大的数开始迭代,这样的话,第一个找到符合条件的回文数也就是最大的了。
接下来,我们需要做的就是在这个由两个n位数组成的回文数中,去看一下它是否存在一个n位数的因子,那么我们要怎么做呢?
这里就借助到 判断一个数是否是素数的思想。
假设我们通过划分左右部分构造出来的回文数为p,如果存在两个n位数a、b,满足ab=p,那么我们可以枚举其中较大的因子x,如果xx>=p,表明可能存在另外一个数y,使得x*y=p。那么,我们怎么知道呢?其实只要 p%x==0就可以了,也就是x是p的因子,那么我们就知道y=p/x了,也就找到结果了
三、代码实现
var largestPalindrome = function (n) {
if (n === 1) return 9;
// 反转字符串
const reverse = s => {
let l = 0, r = s.length - 1
let arr = []
for (let x of s) arr.push(x)
while (l < r) {
let tmp = arr[l]
arr[l] = arr[r]
arr[r] = tmp
l++, r--
}
let res = ''
for (let x of arr) res += x
return res
}
let lower = 1
// 两个位数为n(n>1)的数字的乘积一定是位数为2n的数
// 那么,如果这个数是一个回文数,则可以分解为左右两部分
// 两部分都是一个n位的数字
for (let i = 1; i < n; i++) lower *= 10
// 从大到小遍历,一旦找到符合条件的值,则一定是最大值
for (let l = lower * 10 - 1; l > lower; l--) {
let r = reverse(l + '');
let p = BigInt('' + l + r) //得到回文数
let x = BigInt(lower * 10 - 1);
// 验证当前回文数 9889,是否存在 2~99之间的因子
// 那么怎么判断呢? 这里用到了判断一个数是素数的方法
// 技巧:我们枚举因子中的较大值x(如果因子相同则随便取一个)
// 那么,我们可以考虑一下 x*x与当前构造出来的回文数p之间的关系
// 如果x*x > p代表什么呢? 其实,代表x可能是p的因子
// 同理,x*x=p,代表着当然是 x是p因子了,也就满足题意了
//又或者,x*x<p,就代表不可能存在因子了,因为我们当前枚举的是较大数
while (x * x >= p) {
if (p % x === 0n) return p % 1337n;
x--;
}
}
};
四、总结
以上就是本道题的所有内容了,本系列会持续更,欢迎点赞、关注、收藏,另外如有其他的问题,欢迎下方留言给我,我会第一时间回复你,感谢~