LeetCode 寻找最近的回文数

给定一个整数 n ,你需要找到与它最近的回文数(不包括自身)。
“最近的”定义为两个整数差的绝对值最小。
示例 1:

输入: "123"
输出: "121"

注意:

n 是由字符串表示的正整数,其长度不超过18。
如果有多个结果,返回最小的那个。

思路分析:

如果数组的字符串长度 == 1,数字n - 1
开头为1,9**9为一个候选答案        例:100000,答案为99999
开头为9, 10**01为一个候选答案       例:99999,答案为100001
如果本身对称,则把最中间的一个(或两个)位数减(如果0则加)一
	例:123321,答案为122221
    例:120021,答案为121121
如果不对称:
    把前半部分逆序替换掉后半部分       例:1223,答案为1221
    把最中间的一个(或两个)位数加一   例:1283,答案为1331,而非1221
    把最中间的一个(或两个)位数减一   例:1800,答案为1771,而非1881
class Solution {
public:
	string nearestPalindromic(string n) {
		int strSize = n.size();
		vector<string> candidate;
		if (strSize == 1) {
			//如果数组的字符串长度 == 1,数字n - 1
			return to_string(stoi(n) - 1);
		}
		if (n[0] == '1') {
			//开头为1,9**9为一个候选答案        例:100001,答案为99999
			candidate.push_back(string(strSize - 1, '9'));
		}
		else if (n[0] == '9') {
			//开头为9,10**01为一个候选答案       例:99999,答案为100001
			candidate.push_back('1' + string(strSize - 1, '0') + '1');
		}
		if (isPalindromic(n)) {
			//如果本身对称,则把最中间的一个(或两个)位数减(如果0则加)一
			string temp = n;
			if (strSize % 2) {
				if (temp[strSize / 2] == '0') {
					temp[strSize / 2] += 1;
				}
				else {
					temp[strSize / 2] -= 1;
				}
			}
			else {
				if (temp[strSize / 2] == '0') {
					temp[strSize / 2 - 1] += 1;
					temp[strSize / 2] += 1;
				}
				else {
					temp[strSize / 2 - 1] -= 1;
					temp[strSize / 2] -= 1;
				}
			}
			candidate.push_back(temp);
		}
		else {
			//如果不对称:
			//把前半部分逆序替换掉后半部分       例:1223,答案为1221
			//把最中间的一个(或两个)位数加一   例:1283,答案为1331,而非1221
			//把最中间的一个(或两个)位数减一   例:1800,答案为1771,而非1881
            //先把钱半部分逆序替换到后半部分
			string temp = n.substr(0, strSize / 2), revTemp = temp;
			reverse(revTemp.begin(), revTemp.end());
			if (strSize % 2) {
				temp += n[strSize / 2];
			}
			temp += revTemp;
			candidate.push_back(temp);//"955166082267348992"转换成"955166082280661559"
            //把最中间的一个(或两个)位数加一、减一
			if (strSize % 2) {
				if (temp[strSize / 2] != '0') {
					string strT = temp;
					strT[strSize / 2] -= 1;
					candidate.push_back(strT);
				}
				if (temp[strSize / 2] != '9') {
					string strT = temp;
					strT[strSize / 2] += 1;
					candidate.push_back(strT);
				}
			}
			else {
				if (temp[strSize / 2] != '0') {
					string strT = temp;
					strT[strSize / 2 - 1] -= 1;
					strT[strSize / 2] -= 1;
					candidate.push_back(strT);
				}
				if (temp[strSize / 2] != '9') {
					string strT = temp;
					strT[strSize / 2 - 1] += 1;
					strT[strSize / 2] += 1;
					candidate.push_back(strT);
				}
			}
		}
        //按照数值大小进行升序排序
		sort(candidate.begin(), candidate.end(), myCmp);
        //获取差的绝对值最小的结果
		long long diff = LLONG_MAX, longN = stoll(n);
		string res = "";
		for (auto& tempRes : candidate) {
			long long tempDiff = abs(longN - stoll(tempRes));
			if (tempDiff < diff) {
				diff = tempDiff;
				res = tempRes;
			}
		}
		return res;
	}
    //自定义按照字符串数值大小排序
	static bool myCmp(string & strOne, string & strTwo) {
		if (strOne.size() == strTwo.size()) {
			return strOne < strTwo;
		}
		else {
			return strOne.size() < strTwo.size();
		}
	}
    //判断是否是回文对称
	bool isPalindromic(string & num) {
		int numSize = num.size(), mid = numSize / 2;
		for (int index = 0; index < mid; ++index) {
			if (num[index] != num[numSize - 1 - index]) {
				return false;
			}
		}
		return true;
	}
};

上 面 的 代 码 评 论 区 里 找 出 了 反 例 \color{red}上面的代码评论区里找出了反例

在 55 − 80 行 中 处 理 存 在 漏 洞 , \color{red}在55-80行中处理存在漏洞, 5580

对 于 0 没 有 进 行 − 1 操 作 , 对 于 9 没 有 进 行 + 1 操 作 。 \color{red}对于0没有进行-1操作,对于9没有进行+1操作。 019+1

我们将字符串型修改为long long型进行加、减操作就快捷很多,并且将vector容器修改为set容器,这样就需要额外进行排序。

class Solution {
public: 
    string nearestPalindromic(string n) {
        //set自动升序排序
    	set<long long> candidateSet;
        long long N = stoll(n), strSize = n.size();
        //添加10*01或10**01候选答案
        candidateSet.insert(pow(10, strSize) + 1);
        //添加9*9或9**9候选答案
        candidateSet.insert(pow(10, strSize - 1) - 1);
        
        //如果n的长度是奇数,则最中间的一个位进行加一、减一、不变操作再对称翻转得到三个候选结果
        //比如奇数长度n=“12453”,把中间的4进行三个操作得到"12321"、“12421”、“12521”
        //比如偶数长度n=“124553”,把中间的4进行三个操作得到"123321"、“124421”、“125521”
        //注意偶数长度最中间有两个数位,我们取左边的,因为后面是将左半边的翻转到右半边
        
        //截取n的前一半并转换为long long类型(相比于直接操作字符串更方便些)
        //比如n=“12453”中的124,n=“124553”的124
        long long preHalf = stoll(n.substr(0, (strSize + 1) / 2));
        for (int i = -1; i <= 1; ++i) {
            //获取左半加i的结果
            string leftStr = to_string(preHalf + i);
            //将左半翻转为右半边(如果n长度是奇数,比如n=“12453”,前左半翻转需要剔除最中间的,左半“124”,右半“21”)
            string rightStr = string(leftStr.rbegin() + (strSize % 2), leftStr.rend());
            //合并后转换为long long型放入候选集
            candidateSet.insert(stoll(leftStr + rightStr));
        }
        //候选结果集中可能含有自身,需要剔除
        candidateSet.erase(N);
        //最后在结果集(set升序排列)中查找出最近的回文数
        long long res = -1, diff = LLONG_MAX;
        for (auto tempRes : candidateSet) {
            long long tempDiff = abs(N - tempRes);
            if (tempDiff < diff) {
                diff = tempDiff;
                res = tempRes;
            }
        }
        return to_string(res);
    }
};

在这里插入图片描述
修改为long long类型操作代码简洁了很多。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值