题目描述

✅ 246. 中心对称数

题意分析

判断数字字符串整体旋转 180° 后是否仍与原来完全相同。旋转不仅改变数码的形状,也会把左右位置对调,因此不能只检查每个数码能否旋转。

解法:双指针对称映射

核心思路

[!blue]

合法的旋转关系只有 0 → 0、1 → 1、8 → 8、6 → 9 和 9 → 6。其余数码旋转后无法得到题目要求的有效数码,应直接判定失败。

整体旋转会把左侧位置移到右侧对应位置,所以对称位置必须满足“左字符旋转后的结果等于右字符”。用两个指针分别从首尾向中间移动,每次检查这一对即可,无需构造旋转后的整个字符串。

这些映射互为逆操作:左字符能旋转成右字符,也就保证右字符能旋转回左字符。因此每对只验证一个方向就足够。只要有一对不满足,整体就不可能保持不变;所有对都通过,整个字符串就相同。

循环要包含 left == right。奇数长度的中心位旋转后仍在原位置,只能使用能映射成自身的 0、1、8,不能使用需要与另一种数码配对的 6、9。

解题步骤

  1. 将左右指针分别放在字符串首尾。
  2. 当左指针不超过右指针时,计算左字符的旋转结果。
  3. 若不存在合法映射,或者映射结果不等于右字符,立即返回 false。
  4. 两端同时向内移动一位,直到所有字符对和可能存在的中心位都通过,返回 true。

代码实现

class Solution {
    public boolean isStrobogrammatic(String num) {
        int left = 0;
        int right = num.length() - 1;

        // 包含中心位置,奇数长度的中心也必须旋转后保持不变。
        while (left <= right) {
            char rotated = rotate(num.charAt(left));

            // 无效标记与数字字符零不同,同时检查旋转后的对称字符。
            if (rotated == 0 || rotated != num.charAt(right)) {
                return false;
            }

            left++;
            right--;
        }

        return true;
    }

    private char rotate(char digit) {
        switch (digit) {
            case '0':
            case '1':
            case '8':
                return digit;
            case '6':
                return '9';
            case '9':
                return '6';
            default:
                return 0;
        }
    }
}
func isStrobogrammatic(num string) bool {
    left, right := 0, len(num)-1
    // 包含中心位置,奇数长度的中心也必须旋转后保持不变。
    for left <= right {
        rotated, valid := rotateDigit(num[left])
        // 无效标记与数字字符零不同,同时检查旋转后的对称字符。
        if !valid || rotated != num[right] {
            return false
        }
        left++
        right--
    }
    return true
}

func rotateDigit(digit byte) (byte, bool) {
    switch digit {
    case '0', '1', '8':
        return digit, true
    case '6':
        return '9', true
    case '9':
        return '6', true
    default:
        return 0, false
    }
}

复杂度分析

  • 时间复杂度:$O(n)$,n 为字符串长度,最多检查一半字符对和一个中心位。
  • 空间复杂度:$O(1)$,只使用两个指针和固定的数码映射。

关键点总结

[!green]

  • 整体旋转包含数码映射和位置反转,必须一起检查。
  • 映射互为逆,因此每对只检查左字符到右字符的方向即可。
  • 中心位必须映射成自身,循环不能跳过它。

易错点总结

[!yellow]

  • 只检查字符是否属于 0、1、6、8、9:合法字符仍可能没有与对称位置正确配对。
  • 用普通回文的两端相等判断:6 与 9 应互相配对,不能要求它们相同。
  • 循环使用 left < right:会漏掉奇数长度的中心位检查。
  • 混淆 Java 的无效标记 0 与字符 '0':前者表示没有映射,后者是合法数码;Go 则通过独立的 valid 返回值区分。
  • 只推进一侧指针:之后比较的就不再是互相对应的旋转位置。

相似题目

题目 难度 关联与区别
247. 中心对称数 II 中等 原题生成给定长度的全部中心对称数,本题只按成对映射验证一个字符串。
9. 回文数 简单 普通回文要求两端数码相同,本题旋转180度需要映射配对,6和9可互换。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2024/60913876
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!