【JS】字符串(String)篇——part1

字符串(String)篇——part1

野望发布于 今天 03:42

part1:翻转整数

【JS】字符串(String)篇——part1

心路历程:

1.理解题意:整数、32位、有符号、反转每位数字
2.看懂示例:以上三个示例分别描述了反转、保留符号、去零(如果最高位为0则只保留其他字符)。
3.注意:描述了取值范围,超出范围则返回0

尝试:

1.第一步:判断

2.第二步:翻转
3.第三步:处理

代码如下:

/**

* @description: 翻转整数

* @params {number} str - 传入的整数

* @return {number} 翻转后的整数

*/

function reverse(str) {

let symbol = ""

if (typeof str === "number" && Number.isInteger(str)) {

if (str.toString().length > 32 !== true) {

if (str.toString()[0] === "-") {

symbol = str.toString()[0]

}

// 翻转和处理

let numArr, newStr

if (symbol) {

numArr = [].slice.call(str.toString().slice(1)).reverse()

} else {

numArr = [].slice.call(str.toString()).reverse()

}

newStr = numArr.join("")

for (let i = 0; i < newStr.length; i++) {

if (newStr[i] === "0") {

newStr = newStr.slice(i + 1)

}

i++

}

return parseInt(symbol + newStr)

} else {

return new Error("长度超出限制")

}

} else {

return new Error("非整数")

}

}

console.log(reverse(123)) // 321

console.log(reverse(-123)) // -321

console.log(reverse(120)) // 21

可以看到,按照我分析的思路,以及我现在能够熟练使用的一些方法,已然是自以为是的将它实现了。接下来看看最终答案是什么吧。

终极解决方案————精华来袭:

【JS】字符串(String)篇——part1
代码如下:

/**

* @param {number} x

* @return {number}

*/

const reverse = (x) => {

// 非空判断

if (typeof x !== 'number') {

return;

}

// 极值

const MAX = 2147483647;

const MIN = -2147483648;

// 识别数字剩余部分并翻转

const rest =

x > 0

? String(x)

.split('')

.reverse()

.join('')

: String(x)

.slice(1)

.split('')

.reverse()

.join('');

// 转换为正常值,区分正负数

const result = x > 0 ? parseInt(rest, 10) : 0 - parseInt(rest, 10);

// 边界情况

if (result >= MIN && result <= MAX) {

return result;

}

return 0;

};

分析:
1.思路上:与我的思路基本一致
2.代码上:比我的简洁无数倍,使用的方法也更加准确
3.存在的问题:(1)我的代码首先做了判断整数的处理,但没有判断是否为空的情况;(2)极值的判别片面又草率,题中给出的是数值的取值范围,而我的判断是字符长度,也是明显的答非所问。

代码拆解————深入分析:

1.判别类型及是否为空:

const reverse = (x) => {

// 非空判断

if (typeof x !== 'number') {

console.log(x)

return;

}

}

试问有没有和我一样在判别类型和判别是否为空时使用了两个条件,如:

if (!x) {

return

}

if (typeof x !== "number") {

return

}

// 或

if (!x && typeof x !== "number") {

return

}

在以前我确实没有深入的考虑到typeof x !== "number"这个条件能够进行判空。

现在仔细思考如果传入的值为空的话其实它是undefined,如果是""、null、[]、{}的话,类型又不是number。

所以这样的判空处理确实很聪明。在这种场景下既能确定类型又能确定参数是否为空。

2.极值:

const MAX = 2147483647;

const MIN = -2147483648;

最上面我的代码,在确定边界时简单的判断了参数的长度。很明显是不符合条件的,相信很少有人会犯和我同样的错误。

但是贴这段代码的目的是,我在定义常量的时候总是 const min或const max。这样写当然也可以,但是不够显而易见。通常都是使用全大写的方式。

3.识别数字剩余部分并翻转:

const rest =

x > 0

? String(x)

.split('')

.reverse()

.join('')

: String(x)

.slice(1)

.split('')

.reverse()

.join('');

这段代码太值得学习了,首先是书写风格。我在写三目运算的时候都是一行,很多时候都长到没法看。

其次是使用的方法,准确,准确,准确,我只能这样来形容了。

第一是String(x),使用了一个包装类(其实就是调用了toString()方法,但包装类更简洁清晰)。

第二是split(),这个方法用于字符串分割,我通常是用于处理时间格式等;但精髓在于如果传入的是"",那么它会把字符串的每个字符都分割开来,而且这个方法返回的是一个数组!再对比我自己的方法,还要先使用[].slice.call(x)把它变成数组。惭愧啊,学艺不精啊。

第三是reverse(),这个没什么好说的,数组上的方法用于翻转数组。

第四是join(),把数组的每个元素按照规则拼接成字符串,也很简单。

第五是slice(),按照索引提取字符串的某一个部分,并返回一个新字符串。

4.转换为正常值,区分正负数:

const result = x > 0 ? parseInt(rest, 10) : 0 -parseInt(rest, 10);

怎么说呢,我只能说不怪别人太聪明,只怪自己太愚蠢。我的代码在处理正负整数的时候,首先保留了"-"负号...那正变负不就是0减整数就完事了吗?对不起 x n,代码没写好,数学也没整明白。

parseInt(rest, 10),这里的10是进制,默认就是10进制。所以写作这样也可以:

const result = x > 0 ? parseInt(rest) : 0 - parseInt(rest);

5.边界情况:

if (result >= MIN && result <= MAX) {

return result;

}

return 0;

这个就没什么好说的了。也可以这么写:

return result >= MIN && result <= MAX ? result : 0

复杂度分析:
【JS】字符串(String)篇——part1

巨人的肩膀上好成功,大树底下好乘凉。复盘这段代码确实给我带来了不少的收获。但别急,还有!

【JS】字符串(String)篇——part1

在看到这个方法名的时候我已经被吓到了,这是个嘛?查理 · 芒格曾大致说过,遇到困难的东西要敢于迈步。确实,方法总比困难多,美妙的方法也总是被少数人掌握。

代码如下:

/**

* @param {number} x

* @return {number}

*/

const reverse = (x) => {

// 获取相应数的绝对值

let int = Math.abs(x);

// 极值

const MAX = 2147483647;

const MIN = -2147483648;

let num = 0;

// 遍历循环生成每一位数字

while (int !== 0) {

// 借鉴欧几里得算法,从 num 的最后一位开始取值拼成新的数

num = (int % 10) + (num * 10);

// 剔除掉被消费的部分

int = Math.floor(int / 10);

}

// 异常值

if (num >= MAX || num <= MIN) {

return 0;

}

if (x < 0) {

return num * -1;

}

return num;

};

分析:
1.思路上:欧几里得求最大公约数,看到这句话起初我把重心全放在欧几里得了...但实际上它就是在求最大公约数,这就简单了。然后是翻转,模10取最低位再乘10取最高位,也好理解。
2.代码上:很明显的看到,区别于第一种方法(主要使用String上的方法),这种方法主要使用的是Math上的方法。

代码拆解————深入分析:

1.获取相应数的绝对值

const reverse = (x) => {

let int = Math.abs(x);

}

利用Math.abs将参数处理成正整数。但是这里有一个问题,还是需要判空判类型的,如果不做处理的话Math.abs(x)会返回0或NaN,而且不会抛错,0就不说了,NaN和任何值进行运算都是NaN,所以判空和判类型的处理是必不可少的。改进如下:

const reverse = (x) => {

if (typeof x !== "number") {

return;

}

let int = Math.abs(x)

}

2.极值:

const MAX = 2147483647;

const MIN = -2147483648;

3.遍历循环生成每一位数字:

let num = 0;

while (int !== 0) {

// 借鉴欧几里得算法,从 num 的最后一位开始取值拼成新的数

num = (int % 10) + (num * 10);

// 剔除掉被消费的部分

int = Math.floor(int / 10);

}

while循环确实用的很少,但是不要慌。我们直观的看到循环的入口是int !== 0,而出口是个啥呢?什么时候结束循环呢?

Math.floor()返回小于或等于一个给定数字的最大整数,也就是说当int被消费的很小的时候,int = 0,而此时就会跳出循环了。

回到代码,我们可以代入一个值,比如123。如图:
【JS】字符串(String)篇——part1

看到这里我发现,似乎跟最大公约数没什么关系,反而跟欧几里得算法有点关系...但实际上也很简单。

就按照上面的代入法来一个深入剖析:首先这种方法最精髓的地方就在于while循环内的两行代码。

num这个变量实际上是用来接收int处理结果的变量,而int这个变量是逐渐被“消费”的变量,就好像把一杯水倒进一个空杯子一样。

而在代码上来说,将参数模10,取到的是参数的最低位;而 num * 10 就相当于把num的位数向前推了1位,然后再加上低位数字。然后就相当于做了一次翻转。

【JS】字符串(String)篇——part1

不得不说这个方法真的很巧妙!!!

4.边界情况:

if (num >= MAX || num <= MIN) {

return 0;

}

5.符号:

if (x < 0) {

return num * -1;

}

复杂度分析:
【JS】字符串(String)篇——part1

javascript算法-数据结构

阅读 53更新于 21 分钟前

本作品系原创,采用《署名-非商业性使用-禁止演绎 4.0 国际》许可协议


为了不加班

一个为了写出漂亮代码而努力的前端人

avatar

野望

一个为了写出漂亮代码而努力的前端人

15 声望

2 粉丝

0 条评论

得票时间

avatar

野望

一个为了写出漂亮代码而努力的前端人

15 声望

2 粉丝

宣传栏

part1:翻转整数

【JS】字符串(String)篇——part1

心路历程:

1.理解题意:整数、32位、有符号、反转每位数字
2.看懂示例:以上三个示例分别描述了反转、保留符号、去零(如果最高位为0则只保留其他字符)。
3.注意:描述了取值范围,超出范围则返回0

尝试:

1.第一步:判断

2.第二步:翻转
3.第三步:处理

代码如下:

/**

* @description: 翻转整数

* @params {number} str - 传入的整数

* @return {number} 翻转后的整数

*/

function reverse(str) {

let symbol = ""

if (typeof str === "number" && Number.isInteger(str)) {

if (str.toString().length > 32 !== true) {

if (str.toString()[0] === "-") {

symbol = str.toString()[0]

}

// 翻转和处理

let numArr, newStr

if (symbol) {

numArr = [].slice.call(str.toString().slice(1)).reverse()

} else {

numArr = [].slice.call(str.toString()).reverse()

}

newStr = numArr.join("")

for (let i = 0; i < newStr.length; i++) {

if (newStr[i] === "0") {

newStr = newStr.slice(i + 1)

}

i++

}

return parseInt(symbol + newStr)

} else {

return new Error("长度超出限制")

}

} else {

return new Error("非整数")

}

}

console.log(reverse(123)) // 321

console.log(reverse(-123)) // -321

console.log(reverse(120)) // 21

可以看到,按照我分析的思路,以及我现在能够熟练使用的一些方法,已然是自以为是的将它实现了。接下来看看最终答案是什么吧。

终极解决方案————精华来袭:

【JS】字符串(String)篇——part1
代码如下:

/**

* @param {number} x

* @return {number}

*/

const reverse = (x) => {

// 非空判断

if (typeof x !== 'number') {

return;

}

// 极值

const MAX = 2147483647;

const MIN = -2147483648;

// 识别数字剩余部分并翻转

const rest =

x > 0

? String(x)

.split('')

.reverse()

.join('')

: String(x)

.slice(1)

.split('')

.reverse()

.join('');

// 转换为正常值,区分正负数

const result = x > 0 ? parseInt(rest, 10) : 0 - parseInt(rest, 10);

// 边界情况

if (result >= MIN && result <= MAX) {

return result;

}

return 0;

};

分析:
1.思路上:与我的思路基本一致
2.代码上:比我的简洁无数倍,使用的方法也更加准确
3.存在的问题:(1)我的代码首先做了判断整数的处理,但没有判断是否为空的情况;(2)极值的判别片面又草率,题中给出的是数值的取值范围,而我的判断是字符长度,也是明显的答非所问。

代码拆解————深入分析:

1.判别类型及是否为空:

const reverse = (x) => {

// 非空判断

if (typeof x !== 'number') {

console.log(x)

return;

}

}

试问有没有和我一样在判别类型和判别是否为空时使用了两个条件,如:

if (!x) {

return

}

if (typeof x !== "number") {

return

}

// 或

if (!x && typeof x !== "number") {

return

}

在以前我确实没有深入的考虑到typeof x !== "number"这个条件能够进行判空。

现在仔细思考如果传入的值为空的话其实它是undefined,如果是""、null、[]、{}的话,类型又不是number。

所以这样的判空处理确实很聪明。在这种场景下既能确定类型又能确定参数是否为空。

2.极值:

const MAX = 2147483647;

const MIN = -2147483648;

最上面我的代码,在确定边界时简单的判断了参数的长度。很明显是不符合条件的,相信很少有人会犯和我同样的错误。

但是贴这段代码的目的是,我在定义常量的时候总是 const min或const max。这样写当然也可以,但是不够显而易见。通常都是使用全大写的方式。

3.识别数字剩余部分并翻转:

const rest =

x > 0

? String(x)

.split('')

.reverse()

.join('')

: String(x)

.slice(1)

.split('')

.reverse()

.join('');

这段代码太值得学习了,首先是书写风格。我在写三目运算的时候都是一行,很多时候都长到没法看。

其次是使用的方法,准确,准确,准确,我只能这样来形容了。

第一是String(x),使用了一个包装类(其实就是调用了toString()方法,但包装类更简洁清晰)。

第二是split(),这个方法用于字符串分割,我通常是用于处理时间格式等;但精髓在于如果传入的是"",那么它会把字符串的每个字符都分割开来,而且这个方法返回的是一个数组!再对比我自己的方法,还要先使用[].slice.call(x)把它变成数组。惭愧啊,学艺不精啊。

第三是reverse(),这个没什么好说的,数组上的方法用于翻转数组。

第四是join(),把数组的每个元素按照规则拼接成字符串,也很简单。

第五是slice(),按照索引提取字符串的某一个部分,并返回一个新字符串。

4.转换为正常值,区分正负数:

const result = x > 0 ? parseInt(rest, 10) : 0 -parseInt(rest, 10);

怎么说呢,我只能说不怪别人太聪明,只怪自己太愚蠢。我的代码在处理正负整数的时候,首先保留了"-"负号...那正变负不就是0减整数就完事了吗?对不起 x n,代码没写好,数学也没整明白。

parseInt(rest, 10),这里的10是进制,默认就是10进制。所以写作这样也可以:

const result = x > 0 ? parseInt(rest) : 0 - parseInt(rest);

5.边界情况:

if (result >= MIN && result <= MAX) {

return result;

}

return 0;

这个就没什么好说的了。也可以这么写:

return result >= MIN && result <= MAX ? result : 0

复杂度分析:
【JS】字符串(String)篇——part1

巨人的肩膀上好成功,大树底下好乘凉。复盘这段代码确实给我带来了不少的收获。但别急,还有!

【JS】字符串(String)篇——part1

在看到这个方法名的时候我已经被吓到了,这是个嘛?查理 · 芒格曾大致说过,遇到困难的东西要敢于迈步。确实,方法总比困难多,美妙的方法也总是被少数人掌握。

代码如下:

/**

* @param {number} x

* @return {number}

*/

const reverse = (x) => {

// 获取相应数的绝对值

let int = Math.abs(x);

// 极值

const MAX = 2147483647;

const MIN = -2147483648;

let num = 0;

// 遍历循环生成每一位数字

while (int !== 0) {

// 借鉴欧几里得算法,从 num 的最后一位开始取值拼成新的数

num = (int % 10) + (num * 10);

// 剔除掉被消费的部分

int = Math.floor(int / 10);

}

// 异常值

if (num >= MAX || num <= MIN) {

return 0;

}

if (x < 0) {

return num * -1;

}

return num;

};

分析:
1.思路上:欧几里得求最大公约数,看到这句话起初我把重心全放在欧几里得了...但实际上它就是在求最大公约数,这就简单了。然后是翻转,模10取最低位再乘10取最高位,也好理解。
2.代码上:很明显的看到,区别于第一种方法(主要使用String上的方法),这种方法主要使用的是Math上的方法。

代码拆解————深入分析:

1.获取相应数的绝对值

const reverse = (x) => {

let int = Math.abs(x);

}

利用Math.abs将参数处理成正整数。但是这里有一个问题,还是需要判空判类型的,如果不做处理的话Math.abs(x)会返回0或NaN,而且不会抛错,0就不说了,NaN和任何值进行运算都是NaN,所以判空和判类型的处理是必不可少的。改进如下:

const reverse = (x) => {

if (typeof x !== "number") {

return;

}

let int = Math.abs(x)

}

2.极值:

const MAX = 2147483647;

const MIN = -2147483648;

3.遍历循环生成每一位数字:

let num = 0;

while (int !== 0) {

// 借鉴欧几里得算法,从 num 的最后一位开始取值拼成新的数

num = (int % 10) + (num * 10);

// 剔除掉被消费的部分

int = Math.floor(int / 10);

}

while循环确实用的很少,但是不要慌。我们直观的看到循环的入口是int !== 0,而出口是个啥呢?什么时候结束循环呢?

Math.floor()返回小于或等于一个给定数字的最大整数,也就是说当int被消费的很小的时候,int = 0,而此时就会跳出循环了。

回到代码,我们可以代入一个值,比如123。如图:
【JS】字符串(String)篇——part1

看到这里我发现,似乎跟最大公约数没什么关系,反而跟欧几里得算法有点关系...但实际上也很简单。

就按照上面的代入法来一个深入剖析:首先这种方法最精髓的地方就在于while循环内的两行代码。

num这个变量实际上是用来接收int处理结果的变量,而int这个变量是逐渐被“消费”的变量,就好像把一杯水倒进一个空杯子一样。

而在代码上来说,将参数模10,取到的是参数的最低位;而 num * 10 就相当于把num的位数向前推了1位,然后再加上低位数字。然后就相当于做了一次翻转。

【JS】字符串(String)篇——part1

不得不说这个方法真的很巧妙!!!

4.边界情况:

if (num >= MAX || num <= MIN) {

return 0;

}

5.符号:

if (x < 0) {

return num * -1;

}

复杂度分析:
【JS】字符串(String)篇——part1

以上是 【JS】字符串(String)篇——part1 的全部内容, 来源链接: utcz.com/a/111972.html

回到顶部