Leetcode算法题:字符串转换整数(atoi)

题解:实现 atoi 函数

题目描述:

实现一个 atoi 函数,能够将字符串转换为一个整数。该函数会忽略前导空格,并处理可选的符号(+-),直到遇到非数字字符为止。若字符串中的数字超出了 32 位带符号整数的范围,返回 Integer.MAX_VALUEInteger.MIN_VALUE

题目要求:
  1. 只允许处理数字,符号(+-)以及空格字符。

  2. 返回转换后的整数值。若遇到溢出情况,返回 Integer.MAX_VALUEInteger.MIN_VALUE

  3. 对于无效输入(如字符串中没有数字),返回 0。


解题思路:

  1. 去除前导空格:

    • 根据题目要求,输入字符串可能包含前导空格。我们需要去除这些空格,直到遇到第一个有效字符(数字或符号)。

    • 通过一个 while 循环逐步遍历字符,直到找到第一个非空格字符,更新字符串的起始位置。

  2. 处理符号位:

    • 在去除空格后,可能会遇到一个符号字符(+-)。如果遇到 -,我们需要记住这个符号,之后将转换后的结果乘以 -1。如果遇到 +,则继续处理下一个字符。

    • 注意:这里不能使用 for 循环,因为我们不应该扫描整个字符串中的每一个符号,应该只在符号字符后处理一次符号。

  3. 解析数字:

    • 在处理完符号后,接下来解析字符串中的数字部分。遍历字符直到遇到非数字字符(如字母、空格等)。

    • 每遇到一个数字字符,就将其转换为对应的整数值(通过 charAt(i) - '0')。然后将之前的数字结果乘以 10 并加上当前的数字。

  4. 溢出检查:

    • 在数字解析过程中,需要时刻检查是否会发生溢出。具体来说,如果当前 num 已经大于 Integer.MAX_VALUE / 10,那么再乘以 10 就会溢出。如果 num 等于 Integer.MAX_VALUE / 10,那么还需要进一步检查当前数字是否大于 Integer.MAX_VALUE % 10,以确定是否溢出。

    • 若发生溢出,应该返回 Integer.MAX_VALUEInteger.MIN_VALUE,具体取决于符号。

  5. 返回结果:

    • 将解析出的数字乘上符号(mark)后返回结果。

代码实现:

class Solution {
    public int myAtoi(String s) {
        int mark = 1; // 标记符号,默认为正数
        int num = 0;  // 存储转换后的数字
        int i = 0;    // 遍历字符串的指针
        
        // 1. 去除前导空格
        while (i < s.length() && s.charAt(i) == ' ') {
            i++;
        }
        
        // 2. 如果字符串为空或仅包含空格,返回 0
        if (i == s.length()) {
            return 0;
        }
        
        // 3. 处理符号位
        if (s.charAt(i) == '-') {
            mark = -1;
            i++;
        } else if (s.charAt(i) == '+') {
            i++;
        }
        
        // 4. 解析数字部分
        while (i < s.length() && Character.isDigit(s.charAt(i))) {
            int digit = s.charAt(i) - '0';
            
            // 5. 检查是否发生溢出
            if (num > Integer.MAX_VALUE / 10 || (num == Integer.MAX_VALUE / 10 && digit > Integer.MAX_VALUE % 10)) {
                return mark == 1 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
            }
            
            // 更新数字
            num = num * 10 + digit;
            i++;
        }
        
        // 6. 返回最终结果
        return num * mark;
    }
}

代码分析:

  1. 去除前导空格:

    • 使用 while 循环检查字符串中的每个字符,直到遇到第一个非空格字符。这样,我们可以确保从有效字符开始解析。

  2. 处理符号位:

    • 如果遇到 -,我们将 mark 设置为 -1,表示结果为负数。如果是 +,则继续处理。

    • 对符号的处理只需要一次,因此我们在符号后直接跳过。

  3. 解析数字:

    • 每次遇到数字字符时,通过 charAt(i) - '0' 将字符转换为对应的数字,并累积到 num 变量中。这样就实现了逐位构建整数的功能。

  4. 溢出检查:

    • 在每次更新 num 时,我们先检查是否会发生溢出。如果会溢出,直接返回 Integer.MAX_VALUEInteger.MIN_VALUE

  5. 最终结果:

    • 处理完所有字符后,返回结果 num,并根据符号进行调整。

时间复杂度:

  • 时间复杂度:O(n),其中 n 是字符串 s 的长度。我们只遍历字符串一次,处理每个字符的时间是常数级别的。

  • 空间复杂度:O(1),我们只用了少量的额外空间来存储标记符号、数字结果和遍历指针。

边界情况:

  • 输入为空或只有空格时,返回 0。

  • 输入包含符号 +- 时,正确解析符号。

  • 输入中包含非数字字符时,忽略这些字符,只解析数字部分。

  • 超过整数范围时,返回 Integer.MAX_VALUEInteger.MIN_VALUE

总结:

  • 本题的关键是如何正确地处理前导空格、符号、数字部分的解析以及溢出检测。

  • 通过分步实现每个功能,我们确保了代码的清晰和准确性,同时也考虑了所有可能的边界情况,如溢出、无效字符等。

你可能感兴趣的:(算法,leetcode,职场和发展,java)