对称数(回文)

240 阅读1分钟

1-10000 之间的对称数(回文)

题目

打印 1-10000 之间的对称数

使用数组反转

  • 数字转换为字符串
  • 字符串转换为数组 reverse ,再 join 生成字符串
  • 比较前后的字符串

使用字符串头尾比较

  • 数字转换为字符串
  • 字符串头尾比较

还可以使用(但栈会用到数组,性能不如直接操作字符串)

  • 数字转换为字符串,求长度
  • 如果长度是偶数,则用栈比较
  • 如果长度是奇数,则忽略中间的数字,其他的用栈比较

生成反转数

  • 通过 %Math.floor 将数字生成一个反转数
  • 比较前后的数字

性能分析

时间复杂度看似相当,都是 O(n)

但 方案1 涉及到了数组的转换和操作,就需要耗费大量的时间

  • 数组 reverse 需要时间
  • 数组和字符串的转换需要时间

方案 2 3 比较,数字操作最快。电脑的原型就是计算器,所以处理数字是最快的。

答案

  1. 使用数组反转
/**
 * 查询 1-max 的所有对称数(数组反转)
 * @param max 最大值
 */
export function findPalindromeNumbers1(max: number): number[] {
    const res: number[] = []
    if (max <= 0) return res

    for (let i = 1; i <= max; i++) {
        // 转换为字符串,转换为数组,再反转,比较
        const s = i.toString()
        if (s === s.split('').reverse().join('')) {
            res.push(i)
        }
    }

    return res
}
  1. 字符串头尾比较
/**
 * 查询 1-max 的所有对称数(字符串前后比较)
 * @param max 最大值
 */
export function findPalindromeNumbers2(max: number): number[] {
    const res: number[] = []
    if (max <= 0) return res

    for (let i = 1; i <= max; i++) {
        const s = i.toString()
        const length = s.length

        // 字符串头尾比较
        let flag = true
        let startIndex = 0 // 字符串开始
        let endIndex = length - 1 // 字符串结束
        while (startIndex < endIndex) {
            if (s[startIndex] !== s[endIndex]) {
                flag = false
                break
            } else {
                // 继续比较
                startIndex++
                endIndex--
            }
        }

        if (flag) res.push(i)
    }

    return res
}
  1. 生成反转数
/**
 * 查询 1-max 的所有对称数(翻转数字)
 * @param max 最大值
 */
export function findPalindromeNumbers3(max: number): number[] {
    const res: number[] = []
    if (max <= 0) return res

    for (let i = 1; i <= max; i++) {
        let n = i
        let rev = 0 // 存储翻转数

        // 生成翻转数
        while (n > 0) {
            rev = rev * 10 + n % 10
            n = Math.floor(n / 10)
        }

        if (i === rev) res.push(i)
    }

    return res
}

性能测试:

// 性能测试
console.time('findPalindromeNumbers1')
findPalindromeNumbers1(100 * 10000)
console.timeEnd('findPalindromeNumbers1') // 408ms

console.time('findPalindromeNumbers2')
findPalindromeNumbers2(100 * 10000)
console.timeEnd('findPalindromeNumbers2') // 53ms

console.time('findPalindromeNumbers3')
findPalindromeNumbers3(100 * 10000)
console.timeEnd('findPalindromeNumbers3') // 42ms

划重点

  • 尽量不要使用内置 API ,不好判断时间复杂度
  • 尽量不要转换数据格式,尤其注意数组(有序结构,不能乱来~)
  • 数字操作最快