听风是风

学或不学,知识都在那里,只增不减。

导航

JS leetcode 回文数 题解分析,数学不好是硬伤

壹 ❀ 引

每日一题环节,今天的一道是让我相信自己数学薄弱的题目,题目来源leetcode9. 回文数,题目描述如下:

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:

输入: 121
输出: true

示例 2:

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

示例 3:

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

进阶:

你能不将整数转为字符串来解决这个问题吗?

我们简单分析题目,来看看这道题该怎么做。

贰 ❀ 题解分析

题目进阶是不转字符串来做,我们也别进阶,看看站在字符串的角度能怎么做。

题目关于回文数的描述也很清楚,不管从左还是从右,读起来都相同的数组,那这样无论位数为基数还是偶数,比如22212都死回文数,所以到这里,我第一想到的就是转字符使用双指针来做,先上代码:

/**
 * @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个粉丝了,粉丝数也是回文数!!!!

posted on 2020-06-11 23:46  听风是风  阅读(464)  评论(0编辑  收藏  举报