LeetCode第247题_中心对称数II

LeetCode第247题:中心对称数II

问题描述

中心对称数(Strobogrammatic Number)是指在旋转180度后看起来依然相同的数。例如,数字"69"在旋转180度后看起来仍然是"69",数字"88"旋转后也是"88"。

给定长度为 n 的所有中心对称数的集合。例如,当 n = 2 时,集合包含:“11”,“69”,“88”,“96”。

注意:由于技术限制,我们认为"00"、"10"等不是有效的数字。因此每位数不能以0开头,除非它只有一位且这一位是0。

难度:中等

示例:

示例 1:
输入: n = 2
输出: ["11","69","88","96"]

示例 2:
输入: n = 1
输出: ["0","1","8"]

解题思路

本题需要生成长度为 n 的所有中心对称数。我们先了解一下中心对称数的特性:

  1. 数字0、1、8旋转后仍然是自己
  2. 数字6旋转后是9,数字9旋转后是6
  3. 其他数字旋转后不是有效的数字

我们可以利用递归来解决这个问题。思路如下:

  1. 对于长度为n的中心对称数,其第一位和最后一位必须构成一个合法的中心对称对(不能以0开头,除非n=1)
  2. 中间部分是长度为n-2的中心对称数
  3. 基本情况:
    • 当n=0时,返回空字符串(用于构建偶数长度的中心对称数)
    • 当n=1时,返回可能的单个数字:“0”、“1”、“8”

递归的实现步骤:

  1. 构建长度为n-2的所有中心对称数
  2. 在每个结果的前后添加所有合法的中心对称对:(“0”,“0”), (“1”,“1”), (“8”,“8”), (“6”,“9”), (“9”,“6”)
  3. 注意:如果是整个数字的外层(即原始调用时的n),则不能添加"0"作为开头(只有n=1的特殊情况除外)

代码实现

C#实现

public class Solution {
    public IList<string> FindStrobogrammatic(int n) {
        return Helper(n, n);
    }
    
    private IList<string> Helper(int n, int originalN) {
        // 基本情况
        if (n == 0) return new List<string> { "" }; // 偶数长度的中心
        if (n == 1) return new List<string> { "0", "1", "8" }; // 奇数长度的中心
        
        // 获取中间部分的所有中心对称数
        IList<string> subResults = Helper(n - 2, originalN);
        IList<string> results = new List<string>();
        
        // 在每个结果的前后添加所有合法的中心对称对
        foreach (string subResult in subResults) {
            // 如果不是最外层,可以添加"0"作为开头和结尾
            if (n != originalN) {
                results.Add("0" + subResult + "0");
            }
            
            results.Add("1" + subResult + "1");
            results.Add("8" + subResult + "8");
            results.Add("6" + subResult + "9");
            results.Add("9" + subResult + "6");
        }
        
        return results;
    }
}

Python实现

class Solution:
    def findStrobogrammatic(self, n: int) -> List[str]:
        return self.helper(n, n)
    
    def helper(self, n: int, original_n: int) -> List[str]:
        # 基本情况
        if n == 0:
            return [""]  # 偶数长度的中心
        if n == 1:
            return ["0", "1", "8"]  # 奇数长度的中心
        
        # 获取中间部分的所有中心对称数
        sub_results = self.helper(n - 2, original_n)
        results = []
        
        # 在每个结果的前后添加所有合法的中心对称对
        for sub in sub_results:
            # 如果不是最外层,可以添加"0"作为开头和结尾
            if n != original_n:
                results.append("0" + sub + "0")
            
            results.append("1" + sub + "1")
            results.append("8" + sub + "8")
            results.append("6" + sub + "9")
            results.append("9" + sub + "6")
        
        return results

C++实现

class Solution {
public:
    vector<string> findStrobogrammatic(int n) {
        return helper(n, n);
    }
    
private:
    vector<string> helper(int n, int originalN) {
        // 基本情况
        if (n == 0) return {""};  // 偶数长度的中心
        if (n == 1) return {"0", "1", "8"};  // 奇数长度的中心
        
        // 获取中间部分的所有中心对称数
        vector<string> subResults = helper(n - 2, originalN);
        vector<string> results;
        
        // 在每个结果的前后添加所有合法的中心对称对
        for (const string& sub : subResults) {
            // 如果不是最外层,可以添加"0"作为开头和结尾
            if (n != originalN) {
                results.push_back("0" + sub + "0");
            }
            
            results.push_back("1" + sub + "1");
            results.push_back("8" + sub + "8");
            results.push_back("6" + sub + "9");
            results.push_back("9" + sub + "6");
        }
        
        return results;
    }
};

性能分析

时间复杂度

时间复杂度为 O(5^(n/2)),其中 n 是要生成的中心对称数的长度。这是因为:

  • 我们每次递归调用处理的是长度减少2的子问题
  • 对于每个子问题的结果,我们都要添加5种可能的中心对称对(在某些情况下是4种,但为了上界分析我们考虑5种)
  • 总共有 n/2 层递归调用

空间复杂度

空间复杂度为 O(5^(n/2)),主要用于存储所有生成的中心对称数。此外,递归调用栈的深度为 O(n)。

代码亮点

  1. 巧妙利用递归从内到外构建中心对称数,避免了复杂的迭代逻辑
  2. 使用辅助函数区分递归调用的层次,以便处理特殊情况(如数字不能以0开头)
  3. 递归基本情况的设计考虑了奇数和偶数长度的处理差异

优化方向

  1. 可以使用迭代方法替代递归,减少函数调用的开销
  2. 对于较大的n,可以考虑使用生成器模式,避免一次性存储所有结果

相关题目

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值