[LeetCode] 9. 回文数

引言

对于程序员来说, 算法二字应该都不陌生!!

首先什么是 算法? 它是解决问题的一个思路, 至于使用什么语言去完成不是它的重点, 你可以使用 Java 也可以使用 JS 甚至可以是任何你所熟悉的语言!!

那么我们为什么要学习 算法 呢? 即便我们没研究过它, 我们不是照样一样能完成手头的工作嘛? 其实在工作中, 业务开发过程中, 我们肯定会遇到一个个问题, 并通过编码解决它, 这中间其实或多或少都会用到 算法 只是我们可能对 算法 没怎么研究, 所以并没有感知到!!!

那么学习 算法 到底能给我带来什么呢?

  1. 对于求职者而, 算法 能力能成为你拿到优质 offer 的敲门砖, 不管是大厂还是国外面试都要求有一定 算法 能力
  2. 算法 是解决某类问题的的思路, 通过它可以很好培养我们的逻辑思维能力
  3. 也许在平常工作中你用不到你所学的 算法, 但是当遇到一些复杂问题, 它可以帮助你在复杂的情况中更好地分析问题、解决问题、从而寻找出最优的解决问题的思路
  4. 让我们自己研究 算法 很难, 但是目前很多 算法 都是几代人努力, 研究出来的, 我们可以直接研究学习, 站在巨人的肩膀上成就自我, 何乐而不为呢
  5. 算法 是一种解决问题的思路和方法, 也许有机会应用到生活和事业的其他方面呢
  6. 长期来看, 大脑思考能力是个人最重要的核心竞争力, 而算法是为数不多的能够有效训练大脑思考能力的途径之一

所以相信我, 学习 算法 应该是一件很酷的事情, 所以这里我专门整了个专栏, 希望我能坚持下去吧....

一、题目介绍

地址: leetcode.cn/problems/pa...

  1. 描述:
  • 首先何谓回文数, 回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数, 比如: 121122113231...
  • 本题就是要实现一个方法, 对输入的整数进行判断, 如果该值是个回文整数则返回 true 否则返回 false
  1. 示例:
js 复制代码
示例 1: 
输入: x = 121
输出: true

示例 2: 
输入: x = -121
输出: false
解释: 从左向右读, 为 121 从右向左读, 为 121 因此它不是一个回文数

示例 3: 
输入: x = 10
输出: false
解释: 从右向左读, 为 01 因此它不是一个回文数

二、暴力破解

思路:

  • 首先先将数字转为字符串, 如此是为了方便循环、获取数字(字符)
  • 循环一半的数据, 然后将每一对, 对称的字符进行对比
  • 如果每对, 对称的字符全部相等, 则说明该输入是一个回文数字
js 复制代码
/**
 * @param {number} num
 * @return {boolean}
 */
var isPalindrome = function(num) {
  const strNum = num.toString()  // 转为字符串, 方便处理
  const len = Math.floor(strNum.length / 2) // 计算循环的长度, 最多只需要循环一半的数据即可, 长度为奇数的, 不需要处理中间数字
  
  for (let i = 0; i < len; i ++) {  // 开始循环
    const currentChat = strNum.charAt(i) // 取到当前位置的字符
    const symmetryChat = strNum.charAt(strNum.length - 1 - i) // 取到对称位置的字符
    
    if (currentChat !== symmetryChat) { // 判断, 如果对称的字符不一致, 则不是回文字, 直接返回 false 结束循环
      return false
    }
  }

  // 循环结束, 表示所有对称字符都相等, 则说明输入是回文字, 返回 true
  return true
};

isPalindrome(121) // true

LeetCode 执行结果如下:

三、原生方法

使用 JS 原生方法:

  • 先将数字转为字符串
  • 再将字符串转为数组, 然后使用数组方法对数组进行反转, 然后再转为字符串, 这样就拿到一个反转后的字符串数字
  • 然后将反转的字符串数字和原本的字符串数字进行比较, 如果相等则表示输入的数字是一个回文数字
js 复制代码
/**
 * @param {number} num
 * @return {boolean}
 */
var isPalindrome = function(num) {
  const strNum = num.toString()
  const reverseStrNum = [...strNum].reverse().join('')

  return reverseStrNum === strNum
};

LeetCode 执行结果如下:

四、优雅解法

上面的解法其实都是将 数字转换为字符串, 然后检测字符串是否是回文字, 而这个转换的过程就需要额外的损耗, 不管是时间、还是空间都是有所损耗的!!

如果不转换数字, 我们可能想到的思路就是直接将数字进行反转, 然后和原数字进行对比即可!! 但是这样就会有个问题, 就是在反转数字时可能会出现 整数溢出 问题, 就是反转的数字可能大于 int.MAX

实际上我们并不需要反转全部数字, 我们只需要反转数字的 后半部分, 然后和数字的 前半部分 进行比较即可! 比如:

  • 输入数字是 1221, 我们需要将数字的最后两位 21 进行反转得到数字 12, 然后和数字前半部分 12 进行比较, 发现它们相等, 则说明数字 1221 是个回文数
  • 输入数字是 1231, 我们尝试将数字的最后两位 31 进行反转得到数字 13, 然后和数字前半部分 12 进行比较, 发现它们并不相等则说明数字 1231 不是一个回文数

这里我们需要解决几个问题:

  • 如何循环数字, 并判断何时结束循环?
  • 如何获取数字的最后一位, 并对数字进行反转?
  • 需要注意数字基数位和偶数位的不同情况
  1. 循环我们可以使用 while 来处理, 至于何时结束循环, 只需要对比 反转的数字剩余的数字, 当 反转的数字 大于或等于 剩余的数字 时则结束循环, 因为此时 反转的数字 必然已经过半, 具体代码如下所示, reverseNum 为反转后的数字 num 则为 剩余的数字
js 复制代码
while (num > reverseNum) {
  
}
  1. 这里我们可以使用 num % 10 来获取 num 的最后一个数字, 例如 123 % 10 则会返回数字 123 最后一位数字 3; 至于反转逻辑可以直接看下面代码:
  • 循环外声明变量 reverseNum 用于记录每次反转后的值
  • 循环内每次都会获取当前 num 的最后一位数字 last, 然后作为 reverseNum 的最后一位数值, 做法就是原本的 reverseNum 值乘以 10, 然后加上获取到的 last
  • 最后还需要移除 num 的最后一位数字, 直接除以 10, 然后抹除小数位即可
js 复制代码
let reverseNum = 0

while (num > reverseNum) {
  const last = num % 10 // 取当前 num 最后一位
  reverseNum = reverseNum * 10 + last // 将最后一位加到 reverseNum
  num = Math.floor(num / 10) // 当前 num, 移除最后一位
}
  1. 在循环结束后, 通过判断 numreverseNum 来确定输入是否是回文数字, 这里有两种情况
  • 当输入是偶数位, 则只有当 numreverseNum 完全相等情况下, 才是回文数字
  • 当输入是基数位, 则允许 reverseNumnum 相差一位, 即 num === Math.floor(reverseNum / 10) 情况下输入才是回文数字
js 复制代码
// - num 和 reverseNum 相等, 说明输入是一个偶数位并且是个回文数, 例: 1001、1221
// - Math.floor(reverseNum / 10) 移除 reverseNum 最后一位, 如果值和 num 相等, 说明输入是一个基数位并且是个回文数, 例: 121、434
if (num === reverseNum || num === Math.floor(reverseNum / 10)) {
  return true
}

最后完整编码如下: 在函数开始时还针对特殊情况做了处理, 具体看注释说明

js 复制代码
/**
 * @param {number} num
 * @return {boolean}
 */
var isPalindrome = function(num) {
  // 边界处理: 负数, 肯定不是
  // 非 0 且个位数位 0 肯定不是, 例: 10 110  210
  if (num < 0 || (num !== 0 && num % 10 === 0)) {
    return false
  }

  let reverseNum = 0

  // 循环结束: 循环过半即可
  // - 当 num 等于 reverseNum, 则说明 num 和 reverseNum 长度(位数)相等
  // - 当 num 小于 reverseNum, 则说明 reverseNum 长度(位数)大于或等于 num
  while (num > reverseNum) {
    const last = num % 10 // 取当前 num 最后一位
    reverseNum = reverseNum * 10 + last // 将最后一位加到 reverseNum

    num = Math.floor(num / 10) // 当前 num, 移除最后一位
  }

  // - num 和 reverseNum 相等, 说明输入是一个偶数位并且是个回文数, 例: 1001、1221
  // - Math.floor(reverseNum / 10) 移除 reverseNum 最后一位, 如果值和 num 相等, 说明输入是一个基数位并且是个回文数, 例: 121、434
  if (num === reverseNum || num === Math.floor(reverseNum / 10)) {
    return true
  }

  return false
};


isPalindrome(10)

LeetCode 执行结果如下:

复杂度分析:

  • 时间复杂度: O(log^n)O 对于每次循环, 我们都会将输入除以 10, 因此时间复杂度为 O(log^n)
  • 空间复杂度: O(1) 我们只需要常数空间存放若干变量
相关推荐
YuanLiu_2272 分钟前
代码随想录算法训练营第十三天(递归遍历;迭代遍历;统一迭代;层序遍历)
java·数据结构·笔记·算法·leetcode
闻缺陷则喜何志丹4 分钟前
【C++动态规划】1411. 给 N x 3 网格图涂色的方案数|1844
c++·算法·动态规划·力扣·网格·数目·涂色
蒜蓉大猩猩14 分钟前
Vue.js - 组件化编程
开发语言·前端·javascript·vue.js·前端框架·ecmascript
仙俊红20 分钟前
快速运行openMMOCR
深度学习·算法
Clockwiseee34 分钟前
JS原型、原型链以及原型链污染学习
javascript·学习·原型模式
-Max-静-36 分钟前
Paddle Inference部署推理(十八)
人工智能·windows·深度学习·算法·paddle·推理 部署
王解1 小时前
一篇文章读懂 Prettier CLI 命令:从基础到进阶 (3)
前端·perttier
乐闻x1 小时前
最佳实践:如何在 Vue.js 项目中使用 Jest 进行单元测试
前端·vue.js·单元测试
遇到困难睡大觉哈哈1 小时前
JavaScript面向对象
开发语言·javascript·ecmascript
檀越剑指大厂1 小时前
【Python系列】异步 Web 服务器
服务器·前端·python