
本文详解解决“最近回文数”问题的正确思路与实现:给定数字字符串,返回不等于自身的最近回文整数(距离相同时取较小值),重点修正镜像构造逻辑错误,并提供健壮、边界完备的python实现。
本文详解解决“最近回文数”问题的正确思路与实现:给定数字字符串,返回不等于自身的最近回文整数(距离相同时取较小值),重点修正镜像构造逻辑错误,并提供健壮、边界完备的python实现。
在求解“最近回文数”问题时,核心思想是基于原数的左半部分生成有限个高概率候选回文数,而非暴力遍历——这保证了时间复杂度为 O(log n)。常见错误(如题中所示)往往出在回文构造阶段的索引逻辑:当字符串长度为奇数(如 "123",len=3)时,左半部分为 "12"(取前 (3+1)//2 = 2 位),但镜像时不应包含中间位重复拼接;正确做法是仅将左半部分的前 length//2 位反转后追加。
以 "123" 为例:
-
left_half = "12"(长度为3,(3+1)//2 == 2) - 错误镜像:
"12" + "12"[-(3//2):][::-1]→"12" + "2"[::-1]→"122"(因-(3//2)即-1,切片"12"[-1:] == "2") - 正确镜像:
"12" + "12"[:(3//2)][::-1]→"12" + "1"[::-1]→"121"✅
以下是修正后的完整实现,已覆盖所有关键边界情况:
def nearestPalindromic(n: str) -> str:
original = int(n)
length = len(n)
# 特殊情况:1位数(0~9),最近回文只能是自身±1,但题目要求“not including itself”
# 故 0→"1", 1→"0", 2→"1", ..., 9→"8"
if length == 1:
return str(original - 1) if original > 0 else "1"
# 生成三类核心候选:基于左半部分 ±1 构造的回文,及自身镜像
left_half = n[:(length + 1) // 2]
left_num = int(left_half)
candidates = set()
# 1. 自身镜像回文(可能等于原数,后续过滤)
mirrored = left_half + left_half[:(length // 2)][::-1]
candidates.add(int(mirrored))
# 2. 左半减1后镜像(注意:可能退位,如 "100" → left="10" → "9" → "99")
lower_left = str(left_num - 1)
# 处理退位导致长度变化:如 "1000" (len=4) → left="10" → "9" → 镜像得 "99"(2位),但应为 "999"(3位)?
# 实际上,更稳妥方式是统一按目标长度构造;但此处用 edge_case 覆盖更清晰
if len(lower_left) == len(left_half) or (len(lower_left) == len(left_half) - 1 and lower_left[0] != '0'):
lower_pal = lower_left + lower_left[:(length // 2)][::-1]
candidates.add(int(lower_pal))
# 单独处理全9退位:如 "1000" → 999 是更优候选
candidates.add(10**(length - 1) - 1) # 例如:1000 → 999
# 3. 左半加1后镜像(可能进位,如 "999" → left="99" → "100" → "10001")
upper_left = str(left_num + 1)
if len(upper_left) == len(left_half):
upper_pal = upper_left + upper_left[:(length // 2)][::-1]
candidates.add(int(upper_pal))
# 进位导致长度+1:如 "999" → 1001,"9999" → 10001
candidates.add(10**length + 1)
# 过滤掉原数本身
candidates.discard(original)
# 按绝对差值升序、数值升序(处理平局)选择最优
return str(min(candidates, key=lambda x: (abs(x - original), x)))关键注意事项:
- ✅ 镜像索引必须用
left_half[:(length // 2)][::-1]:确保偶数长取前一半,奇数长舍弃中间位后再反转; - ✅ 必须显式加入两个边缘候选:
10^(k-1)−1(如999)和10^k+1(如10001),它们常在1000、9999等边界击败常规构造; - ⚠️ 单数字场景需单独处理(
"0"→"1","1"→"0"),避免负数或无效字符串; - ⚠️ 使用
set去重,防止lower_pal或upper_pal与edge_case重复(如"100"可能生成多个99)。
该方案通过数学构造替代搜索,在毫秒级内完成任意长度数字的求解,是 LeetCode 564 题的标准最优解法。

















