Swift必学递归技巧!揭秘 LeetCode 247:如何高效生成对称数?

在这里插入图片描述
在这里插入图片描述

摘要

今天我们来聊聊 LeetCode 247 这道题,叫 Strobogrammatic Number II(对称数 II)。简单说,它就是让我们找出所有长度为 n 的对称数——也就是 旋转 180° 后仍然保持原样的数字

这道题的思路很有意思,直接暴力枚举是不行的,我们要用 递归+回溯 来一步步构造答案。本文会 分析题目难点、提供 Swift 代码、解析解法,还会结合实际应用场景,让你彻底搞懂这个问题。

描述

什么是对称数?

对称数就是 旋转 180° 后仍然是原来的数。换句话说,数码在翻转后还能保持原样,比如:

原数字旋转 180° 后
00
11
69
88
96

比如 69,翻转后还是 69,但 12 翻转后变成 21,就不是对称数。

题目示例

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

痛点分析

这道题看似简单,但其实有几个难点:

  1. 不能暴力枚举

    • 比如 n = 2 的情况下,我们可以直接枚举 10-99 的所有两位数,然后挨个判断是不是对称数。但如果 n = 14,那就是 10¹³ 到 10¹⁴ 之间的所有数,范围太大,完全不现实。
  2. 不是所有数字都能用

    • 数字 2, 3, 4, 5, 7 旋转 180° 后没法变成有效的数字,所以这些数字根本不能用,限制了我们的选择。
  3. 递归构造,而不是遍历

    • 我们不能直接从 00 开始找,而是要 从小到大递归地生成,比如:
      1. 先找到 n=0n=1 的基本情况(空字符串 """0""1""8")。
      2. 然后递归地往两边加对称数,比如 "1" + num + "1",形成 n=3 的情况。
  4. 防止前导零

    • n > 1 的情况下,“0” 不能出现在最前面,否则会变成无效数字,比如 “069” 其实是 “69” 而已,不算一个有效的三位数。

Swift 题解

我们使用 递归 + 回溯 解决这个问题,思路是:

  • 先递归生成更短的对称数
  • 再在它们的两边拼接对称数字对("0" + num + "0""1" + num + "1" 等)
class Solution {
    func findStrobogrammatic(_ n: Int) -> [String] {
        return helper(n, n)
    }
    
    private func helper(_ m: Int, _ n: Int) -> [String] {
        if m == 0 { return [""] }
        if m == 1 { return ["0", "1", "8"] }
        
        let subList = helper(m - 2, n)
        var result: [String] = []
        
        for num in subList {
            if m != n { result.append("0" + num + "0") }
            result.append("1" + num + "1")
            result.append("6" + num + "9")
            result.append("8" + num + "8")
            result.append("9" + num + "6")
        }
        
        return result
    }
}

题解代码分析

  1. 递归终止条件

    • m == 0 时,返回 [""](空字符串,用于拼接)。
    • m == 1 时,返回 ["0", "1", "8"],因为单个字符的对称数只有这三个。
  2. 递归构造

    • 先递归生成 更短的对称数,比如 n = 4 时,我们先找到 n = 2 的情况 ["11", "69", "88", "96"]
    • 然后用 五种可能的对称组合 进行扩展:
      • "0" + num + "0"(但不能用于最外层)
      • "1" + num + "1"
      • "6" + num + "9"
      • "8" + num + "8"
      • "9" + num + "6"

示例测试及结果

let solution = Solution()
print(solution.findStrobogrammatic(2))

输出

["11", "69", "88", "96"]

如果 n = 3,会得到:

["101", "111", "181", "609", "619", "689", "808", "818", "888", "906", "916", "986"]

时间复杂度

  • 最坏情况下,每一层递归会产生 5 倍的子问题,总共有 O(n/2) 层递归:
    • 时间复杂度O(5^(n/2))
    • 空间复杂度O(5^(n/2))(存储所有结果)

虽然时间复杂度是指数级的,但 n 最大才 14,计算量还能接受。

实际应用场景

  1. 对称验证码

    • 有些网站会生成特殊验证码,在旋转屏幕时仍然能看清。比如某些验证码可能使用 818609 这类对称数。
  2. 车牌号 & 竞赛车号

    • 在一些比赛中,车号设计要 前后对称,方便观众从不同角度识别,比如 8896 这种数。
  3. 对称性设计

    • 在某些艺术设计、标志、Logo 里,我们可能会用到 旋转对称 的数字,比如某些品牌 Logo 可能采用 6 和 9 互换的效果。

总结

  1. 这道题 不能暴力遍历,要用 递归+回溯 构造解法。
  2. 关键点是 递归构造对称数,并且要 防止前导零
  3. 时间复杂度较高,但 n <= 14 仍然可接受。
  4. 应用场景广泛,从验证码到车牌号、艺术设计,都可能用到类似的对称性概念。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

网罗开发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值