js_algorithm
js_algorithm copied to clipboard
字符串转换整数 (atoi)
leetcode: https://leetcode-cn.com/problems/string-to-integer-atoi/
题目分析
做这道题目大致分为4步
Step1: 计算区间
对应题目描述:
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
用代码描述就是:
// 计算最大值
const max = Math.pow(2,31) - 1
// 计算最小值
const min = -max - 1
Step2: 解析字符串
我们看到这道题,首先可能会想到去遍历字符串,然后依次判断,但仔细想一想,对于字符串的处理用正则来做是不是更好呢?
我这里先把正则给出:
/\s*([-\+]?[0-9]*).*/
下面来分析下:
- 首先,
\s*
,这里的意思就是空格出现0次或多次,都可被匹配到。(对应题目描述该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止
) - 接着是一个
()
,对应正则中就是捕获组
,在这道题里,我们需要从字符串中提取的其实只有+/-
符号以及其后面的数字而已,同时这个字符串需要满足可能存在的空格+正负号+数字字符串+其它字符内容
这样的格式才算合法,那我们就可以通过这样写正则表达式,实现“匹配”和“提取”的双重目的 - 其次,
()
中的内容为[-\+]?[0-9]*
,对应分别是用于匹配-
或+
和0个或多个0-9
之间的整数 - 最后的
.*
用于字符串尾部匹配非数字的任意字符。我们看到.*
是被排除捕获组之外的,所以说这个东西其实也不会被额外存储,它被“摘除”了。
Step3:获取捕获结果
JS
的正则相关方法中, test()
方法返回的是一个布尔值,单纯判断“是否匹配”。要想获取匹配的结果,我们需要调度match()
方法:
const reg = /\s*([-\+]?[0-9]*).*/
const groups = str.match(reg)
match()
方法是一个在字符串中执行查找匹配的String
方法,它返回一个数组,在未匹配到时会返回 null
。
这里match()
会返回第一个完整匹配(作为数组的第0项)及其相关的捕获组(作为数组的第1及第1+项)。
这里我们只定义了一个捕获组,因此可以从 groups[1] 里拿到我们捕获的结果。
判断区间
最后一步,就是把捕获的结果转换成数字,看看是否超出了题目要求的范围。
编码实现
// 入参是一个字符串
const myAtoi = function(str) {
// 编写正则表达式
const reg = /\s*([-\+]?[0-9]*).*/
// 得到捕获组
const groups = str.match(reg)
// 计算最大值
const max = Math.pow(2,31) - 1
// 计算最小值
const min = -max - 1
// targetNum 用于存储转化出来的数字
let targetNum = 0
// 如果匹配成功
if(groups) {
// 尝试转化捕获到的结构
targetNum = +groups[1]
// 注意,即便成功,也可能出现非数字的情况,比如单一个'+'
if(isNaN(targetNum)) {
// 不能进行有效的转换时,请返回 0
targetNum = 0
}
}
// 卡口判断
if(targetNum > max) {
return max
} else if( targetNum < min) {
return min
}
// 返回转换结果
return targetNum
};