[LeetCode] 5933. k 镜像数字的和
一、摘要
本文介绍了一种通过模拟寻找十进制镜像数字,然后判断其对应的k进制表示是否也是镜像的方法。具体来讲即从小到大遍历10进制的镜像数字,然后对10进制镜像数字转为k进制,然后判断转为k进制后是否还满足镜像。题解5933【C++】 800ms 三道简单题的组合对本题已经有较为详细的解释,若读者对本文有所疑问,可以阅读题解5933【C++】 800ms 三道简单题的组合。
二、题解
本题主要分为三个小问题:
- 从小到大遍历10进制镜像数字;
- 将十进制镜像数字转为k进制表达;
- 判断k进制数字表达是否为镜像;
其中小问题2.可以通过求余得到;问题3.可以通过穷举k进制数字各位得到结果。本文将主要对问题1.进行介绍。
为了从小到大遍历10进制镜像数字,我们可以依次讨论不同长度(位数)的数字:
- 对于长度为1的所有10进制数字。所有数字都是镜像的(即数字1,2,3,4,5,6,7,8,9都是镜像的)。
- 对于长度为奇数的10进制数字。例如,长度为5的所有10进制数字,其中镜像数字从小到大一定是:10'0'01, 10'1'01, 10'2'01, ..., 11'0'11, 12'1'21, ..., 99'0'99, ..., 99'9'99。
可以看出,奇数长度的10进制镜像数字可以看成由pre+mid+suf
三部分组成的(使用'符号分割的三部分),而且pre
从10开始直到99,中间的mid
对于任意pre
都是从0到9,而suf
正好是pre
的反转。因此我们可以根据此规律从小到达求得长度为奇数的十进制镜像数字。 - 类似的,对于长度为偶数的十进制数字。例如长度为6的所有十进制数字,其中的镜像数字从小到大一定是:100'001, 101'101, 102'201,..., 999'999。
可以看出偶数长度的十进制镜像数字可以看成pre+suf
两部分,而且pre
从100开始一直到999,suf
为pre
的反转。因此我们也可以根据此规律从小到大求得长度为偶数的10进制镜像数字。
至此,对于不同长度的10进制数字,我们都可以根据相应的规律从小到大求得该长度范围内的镜像数字,然后再判断其转为k进制后是否依旧为镜像数字,找到题目要求的n个满足条件的数字即可。
代码如下:
class Solution {
public:
vector<long long> p = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000};
long long myPow(int n){
return p[n];
}
// 判读数字num的k进制表示是否为镜像
bool isPalindrome(long long num, int k){
string nums; // 注意!此处一定要使用string类型记录各位数字,使用vector<int>会超时
while(num){
nums.push_back(num%k);
num /= k;
}
int n = nums.size();
for(int i=0; i<n/2; i++){
if(nums[i]!=nums[n-1-i]){
return false;
}
}
return true;
}
long long kMirror(int k, int n) {
long long ans = 0;
long long num = 1;
int len = 1;
while(true){
if(len==1){ // 1,2,3,4,5,6,7,8,9
for(int num=1; num<=9; num++){
if(isPalindrome(num, k)){
ans += num;
n --;
if(n<=0){
return ans;
}
}
}
len ++;
}else if(len%2==1){ // 长度为奇数的所有十进制镜像数字
int half_len = len/2;
long long num;
long long mid;
long long suf;
long long min_lit = myPow(half_len-1); // 例如,对于长度为5的数字,pre从10开始遍历到99
long long max_lit = myPow(half_len);
for(long long pre=min_lit; pre<max_lit; pre++){
// 根据pre计算得到suf,suf是pre的反转
long long temp_pre = pre;
long long t = myPow(half_len-1);
suf = 0;
while(temp_pre){
suf += (temp_pre%10)*t;
temp_pre /=10;
t /=10;
}
for(int mid=0; mid<10;mid++){
num = pre*myPow(half_len+1)+mid*myPow(half_len)+suf;
if(isPalindrome(num, k)){
ans += num;
n --;
if(n<=0){
return ans;
}
}
}
}
len ++;
}else{ // 长度为偶数的所有十进制镜像数字
int half_len = len/2;
long long num;
long long suf;
long long min_lit = myPow(half_len-1); // 例如,对于长度为4的数字,pre从10开始遍历到99
long long max_lit = myPow(half_len);
for(long long pre=min_lit; pre<max_lit; pre++){
long long temp_pre = pre;
long long t = myPow(half_len-1);
suf = 0;
while(temp_pre){
suf += (temp_pre%10)*t;
temp_pre /=10;
t /=10;
}
num = pre*myPow(half_len)+suf;
if(isPalindrome(num, k)){
ans += num;
n --;
if(n<=0){
return ans;
}
}
}
len ++;
}
}
return ans;
}
};