564. Find the Closest Palindrome (Hard)

本文介绍了一种寻找给定整数最近回文数的方法。通过分析字符串左右两侧的对称性,构造候选回文数,并从中挑选出与给定整数差值最小的回文数。

原题目:
  Given an integer n, find the closest integer (not including itself), which is a palindrome.
  The ‘closest’ is defined as absolute difference minimized between two integers.

Example 1:
Input: "123"
Output: "121"
Note:
    The input n is a positive integer represented by string, 
    whose length will not exceed 18.
    If there is a tie, return the smaller one as answer.

题目大意如下:
  给定一个整数,找到它“最近”的回文整数,“最近”定义为数值之间差的绝对值最小。
  注意:
  1.整数由string的形式给出;
  2.如果有距离相等的多个数,选择最小的那个。

解题思路:
  首先,我们要理解Palindrome的含义:
  回文,可以看做是将字符串左半部分进行倒转然后覆盖到右半部分,因此我们只需要关注左半部分。
  举个例子:str = 123456
  我们取左半部分substr = 123,题目要求“距离最短”显然,越左代表位数越高差值越大,所以我们考虑最右边的一个数(即原字符串中间的数)。substr1=124,substr2=122,至此我们可以得到3个候选string:
  candidate1 = 12321;
  candidate2 = 12421;
  candidate3 = 12221;
  还没完,如果例子为:88或者10
  显然相对应的我们应该返回101或者9,所以我们应该加入比原字符串多一位的100……001和比原字符串少一位的99……99作为候选
  最后,我们选择candidate数组当中和原数值差值最小的返回就可以了。

代码如下:

class Solution {
public:
    string nearestPalindromic(string n) {
        if(n.empty()) return n ;
        if(n.size() == 1){
            n[0] -= 1 ;
            return n ;
        }
        vector<string> cand ;
        //比n少一位的“99……99”
        cand.push_back(string(n.size() - 1 , '9')) ;

        //比n多一位的“10000……00001”
        string str = n ;
        str[0] = '1' ;
        for(int i = 1 ; i < str.size() ; ++i)
            str[i] = '0' ;
        str.push_back('1') ;
        cand.push_back(str) ;

        //把原字符串变为Palindrome
        str = n ;
        cand.push_back(make_pa(str)) ;
        //把中间字符加一变为Palindrome
        int mid = (str.size() - 1)/2 ;
        str[mid] += 1 ;
        //把中间字符减一变为Palindrome
        cand.push_back(make_pa(str)) ;
        str[mid] -= 2 ;
        cand.push_back(make_pa(str)) ;

        //选取距离最近的那个候选字符串
        long diff = INT_MAX , mark = 0 , temp ;
        for(int i = 0 ; i < cand.size() ; ++i){
            temp = make_diff(cand[i] , n) ;
            if(temp > 0 && temp < diff){
                mark = i ;
                diff = temp ;
            }
            //如果有等距离的,取小的那个
            else if(temp > 0 && temp == diff){
                if(atol(cand[i].c_str()) < atol(cand[mark].c_str())) mark = i ;
            }
        }
        return cand[mark] ;
    }

    //字符串转变为数值然后做差
    long make_diff(string s , string n){
        long count_s = atol(s.c_str()) , count_n = atol(n.c_str()) ;
        return abs(count_s - count_n) ;
    }

    //将字符串变为Palindrome
    string make_pa(string str){
        for(int i = str.size() - 1, j = 0 ; i > (str.size() - 1)/2 ; --i , ++j)
            if(str[i] != str[j]) str[i] = str[j] ;
        return str ;
    }

};

运行结果:
运行结果

知识补充:
1.头文件stdlid.h中函数:
 atoi
 原型:int atoi (const char * str);
 将ascll码(c_string)转换成int类型,因为参数要c_string的头指针所以可以配合strng中的c_str()函数。
 于此同类的函数:atol(返回long int),atoll(返回long long int),atof(返回double)
 例:

long count_s = atol(s.c_str()) , count_n = atol(n.c_str()) ;

2.string中的to_string函数:
string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值