seasongirl 2020-06-12
每日一题环节,今天的一道是让我相信自己数学薄弱的题目,题目来源leetcode9. 回文数,题目描述如下:
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121 输出: true示例 2:
输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。示例 3:
输入: 10 输出: false 解释: 从右向左读, 为 01 。因此它不是一个回文数。进阶:
你能不将整数转为字符串来解决这个问题吗?
我们简单分析题目,来看看这道题该怎么做。
题目进阶是不转字符串来做,我们也别进阶,看看站在字符串的角度能怎么做。
题目关于回文数的描述也很清楚,不管从左还是从右,读起来都相同的数组,那这样无论位数为基数还是偶数,比如22
,212
都死回文数,所以到这里,我第一想到的就是转字符使用双指针来做,先上代码:
/** * @param {number} x * @return {boolean} */ var isPalindrome = function (x) { // 转字符 let x_ = x.toString(), ans = false; // 如果字符串长度为1直接返回 if (x_.length === 1) { return true; }; // 使用双指针 let i = 0, j = x_.length - 1; while (i < j) { // 两两相对,左右同时取数字对比,只要一个不符合直接返回false if (x_.charAt(i) === x_.charAt(j)) { ++i; --j; } else { return ans; }; }; return true; };
那么到这里可以补充两个小知识点,其实大家应该都知道,数字和字符串直接如何快速转换?,单说纯数字类型的字符,转数字可以用 + ,像这样:
+"1"; //1 +"120"; //120
当然用API我们还可以用Number()
,parseInt()
,浮点数还可以使用parseFloat()
。
数字怎么快速转字符呢?我们可以直接用数字加上一个空字符,像这样:
1+""; //"1" 120+""; //"120"
哎,有同学马上想到可以使用toString,没错,不过大家有没有发现一个这样的问题,小数点用toString没问题,整数就报错了,比如:
1.3.toString(); //"1.3" 1.toString(); // 报错 Uncaught SyntaxError: Invalid or unexpected token
你想转整数,你还得这样写:
1..toString(); //"1"
这是因为,当我们写1.toString()
时,JavaScript引擎把第一个点理解成了浮点数,所以在JavaScript看来,它就等同于(1.)toString()
,所以我们得加两个点,可是这样写怪怪的,所以折中的做法是使用括号包裹整数,这样:
(1).toString(); //"1"
很显然,转成字符的思路非常不错,问题来了,既然转成了字符,那为啥不直接再转成数组,做一次翻转了还原直接对比呢,比如这样:
/** * @param {number} x * @return {boolean} */ var isPalindrome = function (x) { return x.toString() === x.toString().split("").reverse().join(""); };
简单明了,比双指针清晰多了。
那么说完转字符串的做法之后,我们会想进阶的问题,能不能就站在数字的角度来解决这个问题呢,老实说,我这种大学没数学的人,敏感度确实差了,这里我先引用leetcode用户吕善柯-三七互娱站在数据角度,使用双指针的解决思路,因为这个是我最能理解一点的...其它数学解答我真的是懵的....我要写个惨字,代码如下:
/** * @param {number} x * @return {boolean} */ var isPalindrome = function(x) { if(x < 0) return false; if(x < 10) return true; let right = 1; let left = 0;//初始为 x的总位数 let sum = x; while(sum >= 1){//算出总位数 sum /= 10; left++; } //获取第n位的数 let getNum = (_x, n) => { return Math.floor(_x % Math.pow(10, n) / Math.pow(10, n - 1)); } while(left > right){ //分别取左右对称两位数字进行对比 if(getNum(x, left) != getNum(x, right)){ return false; }; left--; right++; } return true; };
我之所以希望转字符串,其实本质是想知道需要遍历几次,字符串有length,其次是能便捷获取对应下标的字符。
而上述代码实现中,关于获取length使用的是如下代码:
let left = 0; while (sum >= 1) { //算出总位数 sum /= 10; left++; }
比如数字3223,让这个数不断的除以10,因为一旦比1小,那说明此时数字0.3223了,一共除了4次,说明这是四位数。
知道这个之后我们要做的就是取对应位的数字,比如第一次要取第一位3和最后一位3,可以直接站在答案的角度来说,第一个3就是用3223/1000得到3.223,然后通过floor像下取整拿到3。而最后一位3则是让3223%10,最后得到的3。
所以我觉得我这个脑袋,真的是想不上去的,解题中使用了一个right和left,right表示个位数,是从1开始,而left是总位数,每次比较一个递减一个递增,就这么靠着Math.pow()
这个api以及left与right的变化,就把每次对比的数取出来了,思路我是懂了,就是真的让自己做想不上去,背下来吧估计以后也会忘,我感觉有空我还得学学数学,扎心了。
那么关于本题就分析到这里了。
另外,我有232个粉丝了,粉丝数也是回文数!!!!