力扣564.寻找最近的回文数随笔

良好的方法能使我们更好地发挥天赋的才能,而拙劣的方法则可能阻碍才能的发挥。——贝尔纳

题目

给定一个表示整数的字符串 n ,返回与它最近的回文整数(不包括自身)。如果不止一个,返回较小的那个。

“最近的”定义为两个整数差的绝对值最小。

难度:困难

分析

        我第一次做出这题时,直接做成了“面向测试用例编程”,提交错误了十几次,不断地分类讨论。不过我还是想在这里记录一下每个出错用例,从而总结出正确的方法。容易想到的是为了使绝对值最小,我们应该尽可能从末位数修改,使其与首位数相等。以下是各种用例:

"1"        因为答案不能与自身相同,所以返回为"0"

"10"         "9"和"11"均为回文数,"9"更小应该返回。注意"10"为两位而"9"为一位

"1283"        根据最开始的思路,得到"1221",但是"1331"更接近输入。应当考虑“中间”回文数相邻的回文数

“12389”        与上例相似,"12421"比"12321"更接近输入,看到同样是最中间的数字的变动影响结果

"1837722381"        与上例相似,"1837667381"比"1837777381"更接近输入,注意这里中间的两位数是减小的

"9009"        "8998"比"9119"更接近输入,这里中间的数字是"00",但是仍可以向“外面”的数字“借位”。我做错的原因是只检查中间的两位,以为是"00"就只能改为"11"。同理,"99"也可以“进位”成"00",所以只考虑最中间的两位数或一位数是错误的。

         经过观察和归纳,对答案的构建进行总结:

  • 输入为个位数时,除了"0"的答案为"1",其余为输入减一
  • 取出输入字符串的前半部分(如果位数为奇数则包括中间的数字)x,分别以x,x+1,x-1构建回文数(即补出右半部分),比较结果与输入的差值,注意答案不能与输入相同
  • 特殊判断两种情况:增加一位数得到"10...01";减少一位数得到"9...9"

解答

class Solution {
public:
    string nearestPalindromic(string n) {
        int count=n.length();
        // 一位数特殊讨论
        if (count==1){
            n[0]=n[0]=='0'?'1':n[0]-1;
            return n;
        }
        string pre=n.substr(0,(count+1)/2);  // 取前半部分带中心
        bool valid=1-count%2;
        string ans=create(pre,valid);
        // 不能与原字符串相同
        if (ans==n){
            ans="0";
        }
        int x=stoi(pre);
        // 以x-1构造
        string s1=to_string(x-1);
        string p1=create(s1,valid);
        ans=compare(n,ans,p1);
        // 以x+1构造
        string s2=to_string(x+1);
        string p2=create(s2,valid);
        ans=compare(n,ans,p2);
        // 加1位 10...01
        s1=g1(count+1);
        ans=compare(n,ans,s1);
        // 减1位 9...9
        s2=g9(count-1);
        ans=compare(n,ans,s2);
        return ans;
    }

    string compare(string& origin, string& s1, string& s2){
        long o=stol(origin);
        long n1=stol(s1);
        long n2=stol(s2);
        long x1=abs(n1-o);
        long x2=abs(n2-o);
        if (x1<x2){
            return s1;
        }else if (x2<x1){
            return s2;
        }else{
            return n1<n2?s1:s2;
        }
    }

    string g1(int x){
        string ans="1";
        for (int _=0;_<x-2;_++){
            ans+="0";
        }
        ans+="1";
        return ans;
    }

    string g9(int x){
        string ans;
        for (int _=0;_<x;_++){
            ans+="9";
        }
        return ans;
    }

    string create(string& s, bool lastValid){
        string ans=s;
        int n=s.length();
        for (int i=lastValid?n-1:n-2;i>=0;i--){
            ans+=s[i];
        }
        return ans;
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值