Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情。
1、题目描述
给你一个整数数组 queries 和一个 正 整数 intLength ,请你返回一个数组 answer ,其中 answer[i] 是长度为 intLength 的 正回文数 中第 queries[i] 小的数字,如果不存在这样的回文数,则为 -1 。
回文数 指的是从前往后和从后往前读一模一样的数字。回文数不能有前导 0 。
示例 1:
输入:queries = [1,2,3,4,5,90], intLength = 3
输出:[101,111,121,131,141,999]
解释:
长度为 3 的最小回文数依次是:
101, 111, 121, 131, 141, 151, 161, 171, 181, 191, 201, ...
第 90 个长度为 3 的回文数是 999 。
示例 2:
输入:queries = [2,4,6], intLength = 4
输出:[1111,1331,1551]
解释:
长度为 4 的前 6 个回文数是:
1001, 1111, 1221, 1331, 1441 和 1551 。
提示:
1 <= queries.length <= 5 * 10^4
1 <= queries[i] <= 10^9
1 <= intLength <= 15
2、思路分析
本题为leetcode第 286 场周赛的第三题,难度定位为中等。
这道题其实不难,只要可以找出回文数构成的规律我们就可以很快的解决这道题目。
我们看到4位数的数字可以构成的个数总有9*10*10*10 = 9000个
那么里面有多少个回文数呢?
回文数 指的是从前往后和从后往前读一模一样的数字。回文数不能有前导 0 。
所以我们可以得出:
由回文数的性质我们可以将数据范围缩小至9*10 = 90个
我们只需要确定前半部分的数字,再使用前半部分的数字对照得出后半部分的数字即可。
具体步骤如下:
- 前半部分长度 如长度len为4的我们需要确定前2位,长度为3的我们也需要确认前2位的值。
let l = Math.ceil(len / 2) - 1;
- 判断是否能有足够多的组成方式
总共可以组成满足条件的数目如上图所示,应该为:
9 * Math.pow(10,l)
if(num > 9 * Math.pow(10,l)) return -1;
- 计算出前半部分每一位的数字
每确认完一个位置,就要将数据范围缩小至下一个位置的数据范围,即
num -= (count - 1) * Math.pow(10,l - i);
let res = '';
for(let i = 0; i <= l; i++){
let count = Math.ceil(num / Math.pow(10,l - i));
num -= (count - 1) * Math.pow(10,l - i);
res += i == 0 ? count : count - 1;
}
- 补全后半部分的数字 需要判断数字长度,为奇数时我们需要忽略前半部分的最后一位。
if(len % 2 == 1) l--;
while(l >= 0){
res += res[l];
l--;
}
3、AC代码
/**
* @param {number[]} queries
* @param {number} intLength
* @return {number[]}
*/
var kthPalindrome = function(que, len) {
const ans = [];
const getNum = function(num,len){
let l = Math.ceil(len / 2) - 1;
if(num > 9 * Math.pow(10,l)) return -1;
let res = '';
for(let i = 0; i <= l; i++){
let count = Math.ceil(num / Math.pow(10,l - i));
num -= (count - 1) * Math.pow(10,l - i);
res += i == 0 ? count : count - 1;
}
if(len % 2 == 1) l--;
while(l >= 0){
res += res[l];
l--;
}
return res;
}
for(let i = 0; i < que.length;i++){
ans.push(getNum(que[i],len));
}
return ans;
};