题目描述:
请你来实现一个 atoi
函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
- 如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
- 假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
- 该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
- 本题中的空白字符只包括空格字符
' '
。 - 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例1:
输入: "42"
输出: 42
示例2:
输入: " -42"
输出: -42
解释:第一个非空白字符为 '-', 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例3:
输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例4:
输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。
因此无法执行有效的转换。
示例5:
输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
难度:
- 难度:中等
- 支持语言:JavaScript、Java、Python
相关标签
- 字符串
- 数学
相关企业
- 阿里
- 大疆
- 腾讯
思路 1(javascript):
这道题涉及的情况有4种,因此需要先完全考虑清楚它们的关系,否则会容易漏掉一些规则出错。
- 空格:空格只有在前面没有任何字符的情况下才能继续处理,如果前面存在任何字符,遇到空格直接跳出。
- 字母:遇到字母直接跳出。
- 正负号:只有在还没有出现正负号或者数字的情况,正负号才有效,否则跳出。
- 数字:遇到数字如果前面无zhengfuhao正负号,说明是正号。
思路 2:
字符串处理的题目往往涉及复杂的流程以及条件情况,如果直接上手写程序,一不小心就会写出极其臃肿的代码。
因此,为了有条理地分析每个输入字符的处理方法,我们可以使用自动机这个概念:
我们的程序在每个时刻有一个状态
s
,每次从序列中输入一个字符c
,并根据字符c
转移到下一个状态s
'。这样,我们只需要建立一个覆盖所有情况的从s
与c
映射到s
' 的表格即可解决题目中的问题。
思路 3:
- 使用正则表达式:
^:匹配字符串开头
[\+\-]:代表一个+字符或-字符
?:前面一个字符可有可无
\d:一个数字
+:前面一个字符的一个或多个
\D:一个非数字字符
*:前面一个字符的0个或多个
max(min(数字, 231 - 1), -231) 用来防止结果越界
为什么可以使用正则表达式?如果整数过大溢出怎么办?
首先,这个假设对于 Python 不成立,Python 不存在 32 位的 int 类型。其次,即使搜索到的字符串转32位整数可能导致溢出,我们也可以直接通过字符串判断是否存在溢出的情况(比如 try 函数 或 判断字符串长度 + 字符串比较)~
复杂度分析
- 时间复杂度:O(N)O(N),这里 NN 为字符串的长度;
- 空间复杂度:O(1)O(1)。
代码
JavaScript 实现
/**
* @来源:Javascript中文网 - 前端进阶资源教程 https://www.javascriptc.com/
* @介绍:一个致力于帮助开发者用代码改变世界为使命的平台,每天都可以在这里找到技术世界的头条内容
* @param {string} str
* @return {number}
*/
var myAtoi = function(str) {
let isNeg=null
let first=false
let numS=0
for(let i=0;i<str.length;i++){
if(!first && str[i]===' ')continue
first=true
if(isNeg==null && str[i]==="+"){
isNeg=false
}else if(isNeg==null && str[i]==="-"){
isNeg=true
}else if(/\d/.test(str[i])){
isNeg=!!isNeg
numS=numS*10+str[i]*1
}else{
break
}
}
let res=isNeg?-numS:numS,
limit=Math.pow(2,31)
if(res>limit-1)res=limit-1
if(res<-limit)res=-limit
return res
};
/**
* @作者:gatsby-23
* @链接:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/javascripttou-ji-qu-qiao-wu-xu-si-kao-yi-kan-jiu-h/
* @param {string} str
* @return {number}
*/
var myAtoi = function(str) {
const number = parseInt(str, 10);
if(isNaN(number)) {
return 0;
} else if (number < Math.pow(-2, 31) || number > Math.pow(2, 31) - 1) {
return number < Math.pow(-2, 31) ? Math.pow(-2, 31) : Math.pow(2, 31) - 1;
} else {
return number;
}
};
/**
* @作者:liu-zi-qian-2
* @链接:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/8-zi-fu-chuan-zhuan-huan-zheng-shu-atoi-by-liu-zi-/
* @param {string} str
* @return {number}
*/
var myAtoi = function(str) {
str = str.trim();
if(!/^[+|-]?\d+/.test(str)) return 0;
let val = parseInt(str.match(/^[+|-]?\d+/));
let base = Math.pow(2,31)
let min = -base;
let max = base-1;
return Math.max(Math.min(val, max), min)
};
Java 实现
/**
* @作者:liweiwei1419
* @链接:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/jin-liang-bu-shi-yong-ku-han-shu-nai-xin-diao-shi-/
*/
public class Solution {
public int myAtoi(String str) {
int len = str.length();
// str.charAt(i) 方法回去检查下标的合法性,一般先转换成字符数组
char[] charArray = str.toCharArray();
// 1、去除前导空格
int index = 0;
while (index < len && charArray[index] == ' ') {
index++;
}
// 2、如果已经遍历完成(针对极端用例 " ")
if (index == len) {
return 0;
}
// 3、如果出现符号字符,仅第 1 个有效,并记录正负
int sign = 1;
char firstChar = charArray[index];
if (firstChar == '+') {
index++;
} else if (firstChar == '-') {
index++;
sign = -1;
}
// 4、将后续出现的数字字符进行转换
// 不能使用 long 类型,这是题目说的
int res = 0;
while (index < len) {
char currChar = charArray[index];
// 4.1 先判断不合法的情况
if (currChar > '9' || currChar < '0') {
break;
}
// 题目中说:环境只能存储 32 位大小的有符号整数,因此,需要提前判:断乘以 10 以后是否越界
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && (currChar - '0') > Integer.MAX_VALUE % 10)) {
return Integer.MAX_VALUE;
}
if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && (currChar - '0') > -(Integer.MIN_VALUE % 10))) {
return Integer.MIN_VALUE;
}
// 4.2 合法的情况下,才考虑转换,每一步都把符号位乘进去
res = res * 10 + sign * (currChar - '0');
index++;
}
return res;
}
public static void main(String[] args) {
Solution solution = new Solution();
String str = "2147483646";
int res = solution.myAtoi(str);
System.out.println(res);
System.out.println(Integer.MAX_VALUE);
System.out.println(Integer.MIN_VALUE);
}
}
import java.util.regex.*;
class Solution {
public int myAtoi(String str) {
//清空字符串开头和末尾空格(这是trim方法功能,事实上我们只需清空开头空格)
str = str.trim();
//java正则表达式
Pattern p = Pattern.compile("^[\\+\\-]?\\d+");
Matcher m = p.matcher(str);
int value = 0;
//判断是否能匹配
if (m.find()){
//字符串转整数,溢出
try {
value = Integer.parseInt(str.substring(m.start(), m.end()));
} catch (Exception e){
//由于有的字符串"42"没有正号,所以我们判断'-'
value = str.charAt(0) == '-' ? Integer.MIN_VALUE: Integer.MAX_VALUE;
}
}
return value;
}
}
/**
* @作者:sweetiee
* @链接:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/java-zi-fu-chuan-zhuan-zheng-shu-hao-dong-by-sweet/
*/
public class Solution {
public int myAtoi(String str) {
char[] chars = str.toCharArray();
int n = chars.length;
int idx = 0;
while (idx < n && chars[idx] == ' ') {
// 去掉前导空格
idx++;
}
if (idx == n) {
//去掉前导空格以后到了末尾了
return 0;
}
boolean negative = false;
if (chars[idx] == '-') {
//遇到负号
negative = true;
idx++;
} else if (chars[idx] == '+') {
// 遇到正号
idx++;
} else if (!Character.isDigit(chars[idx])) {
// 其他符号
return 0;
}
int ans = 0;
while (idx < n && Character.isDigit(chars[idx])) {
int digit = chars[idx] - '0';
if (ans > (Integer.MAX_VALUE - digit) / 10) {
// 本来应该是 ans * 10 + digit > Integer.MAX_VALUE
// 但是 *10 和 + digit 都有可能越界,所有都移动到右边去就可以了。
return negative? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
ans = ans * 10 + digit;
idx++;
}
return negative? -ans : ans;
}
}
Python 实现
# 作者:QQqun902025048
# 链接:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/python-1xing-zheng-ze-biao-da-shi-by-knifezhu/
class Solution:
def myAtoi(self, s: str) -> int:
return max(min(int(*re.findall('^[\+\-]?\d+', s.lstrip())), 2**31 - 1), -2**31)
# @作者:yun-yu-chen
# @链接:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/san-chong-fang-fa-zheng-chang-bian-li-you-xian-zhu/
class Solution:
def myAtoi(self, str: str) -> int:
i=0
n=len(str)
while i<n and str[i]==' ':
i=i+1
if n==0 or i==n:
return 0
flag=1
if str[i]=='-':
flag=-1
if str[i]=='+' or str[i]=='-':
i=i+1
INT_MAX=2**31-1
INT_MIN=-2**31
ans=0
while i<n and '0'<=str[i]<='9':
ans=ans*10+int(str[i])-int('0')
i+=1
if(ans-1>INT_MAX):
break
ans=ans*flag
if ans>INT_MAX:
return INT_MAX
return INT_MIN if ans<INT_MIN else ans
# @作者:yi-wen-statistics
# @链接:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/wo-shi-liao-19ci-ni-men-ni-by-yi-wen-statistics/
class Solution:
def myAtoi(self, s: str) -> int:
'''
自定义匹配规则(自上而下,按顺序排除特殊情况):
1. 将第一个字符为非有效字符的字符串、空白字符串、不含数字的字符串以及空字符串排除
2. 如果第一位是正负号,此时它后面必须为数字,否则一定无效
3. 如果第一位是正负号,那么扫描出有效整数
4. 如果第一位是数字,那么同样扫描出有效整数
5. 得出有效整数以后,需要排除前置0
6. 输出结果
'''
# 第一步
countInvalidChar = 0
judgeFirstChar = False
firstChar = '';
firstCharIndex = -1;
for charIndex in range(len(s)):
if s[charIndex] != ' ' and s[charIndex] in "-+0123456789" and not judgeFirstChar:
firstChar = s[charIndex]
firstCharIndex = charIndex
judgeFirstChar = True
if s[charIndex] != ' ' and s[charIndex] not in "-+0123456789" and not judgeFirstChar:
judgeFirstChar = True
return 0
if s[charIndex] in "-+0123456789":
countInvalidChar += 1
if countInvalidChar == 0:
return 0
# 第二步
if firstChar in "-+":
if firstCharIndex+1 == len(s):
return 0
else:
if s[firstCharIndex+1] not in "0123456789":
return 0
else: # 第三步
i = firstCharIndex+1 # 设定指针,扫描charIndex后的数据
invalidInteger = firstChar
while i < len(s) and s[i] in "0123456789":
invalidInteger += s[i]
i += 1
else: # 第四步
j = firstCharIndex+1
invalidInteger = firstChar
while j < len(s) and s[j] in "0123456789":
invalidInteger += s[j]
j += 1
# 第六步
return self.outputFinalInteger(invalidInteger)
# 第五步
def outputFinalInteger(self, invalidInteger):
if invalidInteger[0] in "-+":
finalInteger = invalidInteger[0]
i = 1 # 设置指针,扫描出不含前置0的整数
while i < len(invalidInteger) and invalidInteger[i] == 0:
i += 1
finalInteger += invalidInteger[i:]
return min(max(int(finalInteger), -2**31), 2**31-1)
else:
return min(max(int(invalidInteger), -2**31), 2**31-1)
其他
- 原题leetcode链接:https://leetcode-cn.com/problems/string-to-integer-atoi/
- 合作方:JavaScript中文网 – 全球极客挚爱的技术成长平台
- 说明:leetcode 题解 | 每日一题