
本文详解如何正确构造候选回文数,重点修正镜像拼接逻辑错误,并提供健壮、边界完备的python实现,适用于任意正整数字符串输入。
本文详解如何正确构造候选回文数,重点修正镜像拼接逻辑错误,并提供健壮、边界完备的python实现,适用于任意正整数字符串输入。
求解“最近回文数”是一道经典的构造型算法题:给定一个表示非负整数的字符串 n,需返回不等于自身的、与之绝对差值最小的回文整数;若存在差值相等的两个回文数,则返回较小者。
核心思路是:所有可能的“最近回文”必然源于对原数左半部分(含中位)的微小扰动——即仅尝试将左半部分 ±1 或保持不变后镜像生成回文,再辅以两类关键边界候选(如 999... 和 100...001),从而在 O(1) 个候选中选出最优解。
但原始代码存在一个关键错误:镜像拼接逻辑不统一。例如对 "123"(长度为 3):
-
left_half = "12"((3+1)//2 = 2,取前2位); - 错误写法
left_half[-(length // 2):][::-1]→"12"[-1:][::-1]→"2"[::-1]→"2",得"12"+"2" = "122"❌; - 正确写法应取左半部分的前
length//2位再反转:left_half[:(length // 2)][::-1]→"12"[:1][::-1]→"1"[::-1]→"1",得"12"+"1" = "121"✅。
以下是修正后的完整实现,已通过全部边界用例(如 "1", "9", "10", "99", "100", "123" 等):
def nearestPalindromic(n: str) -> str:
original_n = int(n)
length = len(n)
# 特殊情况:单数字(注意:'1'→'0','0'→'1',但题目隐含n为正整数,通常n≥1)
if length == 1:
return str(original_n - 1)
# 提取左半部分(含中位,长度为 (length + 1) // 2)
left_len = (length + 1) // 2
left_half = n[:left_len]
# 构造三类基于左半部分的候选回文
candidates = set()
# 1. 原左半部分镜像(可能等于自身,后续过滤)
left_num = int(left_half)
def make_palindrome(left_str: str) -> int:
# 取 left_str 的前 length//2 位并反转,拼接到 left_str 后
half_to_mirror = left_str[:length // 2]
mirrored_right = half_to_mirror[::-1]
return int(left_str + mirrored_right)
candidates.add(make_palindrome(left_half))
# 2. 左半部分 -1(注意:可能降位,如 "100"→"99")
lower_left = str(left_num - 1)
# 处理降位导致长度变化(如 "100"→"99",原left_len=2,现"99"长度仍为2;但"10"→"9"需补全?实际无需,make_palindrome会按当前字符串处理)
if lower_left == "0" and length == 2: # "10" → "0" → "0" + "" = "0" → 0,合理
candidates.add(0)
else:
candidates.add(make_palindrome(lower_left))
# 3. 左半部分 +1
upper_left = str(left_num + 1)
candidates.add(make_palindrome(upper_left))
# 4. 边界候选:形如 999...9(比n少一位的最大回文)
candidates.add(10 ** (length - 1) - 1)
# 5. 边界候选:形如 100...001(比n多一位的最小回文)
candidates.add(10 ** length + 1)
# 过滤掉原数本身,并找出最优解
candidates = [c for c in candidates if c != original_n]
return str(min(candidates, key=lambda x: (abs(x - original_n), x)))
关键注意事项:
-
make_palindrome中镜像段必须是left_str[:length//2][::-1],确保偶/奇长度均正确(如"1234"→"12"+"21","123"→"12"+"1"); - 边界候选
10**(length-1)-1(如"100"→99)和10**length+1(如"99"→101)不可或缺,否则"1000"会漏掉"999"; - 使用
set避免重复候选(如"999"的left_half="99",+1→"100",镜像得"10001",而10**4+1也是"10001"); - 单数字特判返回
n-1(因"1"最近回文是"0",而非"1"自身;题目要求“not including itself”)。
该方案时间复杂度 O(log n),空间 O(1),逻辑清晰且鲁棒性强,是解决此类构造回文问题的标准范式。










