[LeetCode] 5933. k 镜像数字的和

一、摘要

敬告:本人博客将迁移至博客园刘好念的博客!!!以后将逐渐弃用CSDN。

本文介绍了一种通过模拟寻找十进制镜像数字,然后判断其对应的k进制表示是否也是镜像的方法。具体来讲即从小到大遍历10进制的镜像数字,然后对10进制镜像数字转为k进制,然后判断转为k进制后是否还满足镜像。题解5933【C++】 800ms 三道简单题的组合对本题已经有较为详细的解释,若读者对本文有所疑问,可以阅读题解5933【C++】 800ms 三道简单题的组合

二、题解

本题主要分为三个小问题:

  1. 从小到大遍历10进制镜像数字;
  2. 将十进制镜像数字转为k进制表达;
  3. 判断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,sufpre的反转。因此我们也可以根据此规律从小到大求得长度为偶数的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;
    }
};

三、参考

[1.] 5933【C++】 800ms 三道简单题的组合

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值