Loading

字符串转换整数 (atoi)

请你来实现一个 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) 。

解法一:正常遍历

 这个问题其实没有考察算法的知识,模拟的是日常开发中对于原始数据的处理(例如「参数校验」等场景),注意写清楚注释、体现逻辑层次。

代码如下:
public int myAtoi(String str) {
    int len = str.length();
    char[] chars = str.toCharArray();
    //1.去除无用的开头空格字符
    int index = 0;
    while (index < len && chars[index] == ' ') {
        index++;
    }
    //2.如果已经遍历完成
    if (index == len) {
        return 0;
    }
    //3.判断是否正负号
    int sign = 1;
    if (chars[index] == '+') {
        index++;
    } 
    if (chars[index] == '-') {
        sign = -1;
        index++;
    }
    //4.取数字并判断是否溢出
    int res = 0;
    while (index < len) {
        char currChar = chars[index];
        if (currChar > '9' || currChar < '0') {
            break;
        }
        //判断是否越界
        if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE && currChar - '0' > Integer.MAX_VALUE % 10)) {
            return Integer.MAX_VALUE;
        } else if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE && currChar - '0' > -(Integer.MIN_VALUE % 10))) {
            return Integer.MIN_VALUE;
        }
        res = res * 10 + sign * (currChar - '0');
        index++;
    }
    return res;
}

解法二:有限状态机

 在本题中一共有四种状态,每种状态遇到空格,符号,数字、其他又会转入不同的状态。状态转换表如下所示:

' ' +/- nubmer other
start strat sign in_number end
sign end end in_number end
in_number end end in_number end
end end end end end
代码如下
//自动机模型
class Automata {
    private int state = 0;
    private int[][] table = {{0, 1, 2, 3},{3, 3, 2, 3},{3, 3, 2, 3},{3, 3, 3, 3}};
    long ans = 0;
    int sign = 1;

    public int getCol(char c) {
        if(c == ' ') {
            return 0;
        }
        if(c == '+' || c == '-'){
            return 1;
        }
        if(Character.isDigit(c)){
            return 2;
        }
        return 3;
    }

    public void get(char c) {
        state = table[state][getCol(c)];
        if(state == 1){
            if (c == '-') {
                sign = -1;
            } else {
                sign = 1;
            }
        }
        if(state == 2){
            ans = ans * 10 + (c - '0');
            ans = sign == 1 ? Math.min(ans, (long) Integer.MAX_VALUE) : Math.min(ans, -(long) Integer.MIN_VALUE);
        }
    }
}
class Solution {
    public int myAtoi(String s) {
        Automata automata = new Automata();
        char[] str = s.toCharArray();
        for(char ch : str){
            automata.get(ch);
        }
        return (int)automata.ans * automata.sign;
    }
}
  • 时间复杂度 O(N),空间复杂度 O(1)

解法三:正则表达式

 对于本题,这里我们如果应用正则表达式把数字那一串提取出来再进行处理就简单多了,需要注意的是当前环境只能存储 32 位大小的有符号整数。
 关于正则表达式,可以看这篇https://www.zhihu.com/question/48219401/answer/742444326

代码如下
    public int myAtoi(String str) {
        String pattern = "^\\s*([+-]?\\d+)";
        Pattern r = Pattern.compile(pattern);
        Matcher m = r.matcher(str);
        if(!m.find()) return 0;
        char[] chars = m.group(1).toCharArray();
        int res = 0;
        int index = 0;
        int sign = 1;
        if (chars[index] == '+') {
            index++;
        } else if (chars[index] == '-') {
            sign = -1;
            index++;
        }
        while(index < chars.length){
            char currChar = chars[index];
            if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && (currChar - '0') > Integer.MAX_VALUE % 10)) {
                return Integer.MAX_VALUE;
            } else if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && (currChar - '0') > -(Integer.MIN_VALUE % 10))) {
                return Integer.MIN_VALUE;
            }
            res = res * 10 + sign * (currChar - '0');
            index++;
        }
        return res;
    }
posted @ 2020-08-12 10:04  水纸杯  阅读(199)  评论(1)    收藏  举报