博客 / 詳情

返回

劍指offer-49、把字符串轉換成整數

題⽬描述

請你來實現⼀個 myAtoi(string s) 函數,使其能將字符串轉換成⼀個 32 位有符號整數(類似C/C++ 中的 atoi 函數)。

函數 myAtoi(string s) 的算法如下:

  • 讀⼊字符串並丟棄⽆⽤的前導空格
  • 檢查下⼀個字符(假設還未到字符末尾)為正還是負號,讀取該字符(如果有)。 確定最終結果是負數,還是正數。 如果兩者都不存在,則假定結果為正。
  • 讀⼊下⼀個字符,直到到達下⼀個⾮數字字符或到達輸⼊的結尾。字符串的其餘部分將被忽略。
  • 將前⾯步驟讀⼊的這些數字轉換為整數(即," 123 " -> 123 , " 0032 " -> 32 )。
  • 如果沒有讀⼊數字,則整數為 0 。必要時更改符號(從步驟 2 開始)。
  • 如果整數數超過 32 位有符號整數範圍 [−2^31, 2^(31 − 1)] ,需要截斷這個整數,使其保持在這個範圍內。具體來説,⼩於 −2^31 的整數應該被固定為 2^31 ,⼤於 2^(31 − 1) 的整數應該被固定為2^(31 − 1)
  • 返回整數作為最終結果。

注意:

  • 本題中的空⽩字符只包括空格字符 ' ' 。
  • 除前導空格或數字後的其餘字符串外,請勿忽略 任何其他字符。

示例1:
輸⼊:s = "42"
輸出:42
解釋:加粗的字符串為已經讀⼊的字符,插⼊符號是當前讀取的字符。

  1. 第 1 步:"42"(當前沒有讀⼊字符,因為沒有前導空格)
  2. 第 2 步:"42"(當前沒有讀⼊字符,因為這⾥不存在 '-' 或者 '+')
  3. 第 3 步:"42"(讀⼊ "42")
  4. 解析得到整數 42 。
  5. 由於 "42" 在範圍 [-231, 231 - 1] 內,最終結果為 42 。

示例2:
輸⼊:s = " -42"
輸出:-42
解釋:

  1. 第 1 步:" -42"(讀⼊前導空格,但忽視掉)
  2. 第 2 步:" -42"(讀⼊ '-' 字符,所以結果應該是負數)
  3. 第 3 步:" -42"(讀⼊ "42")
  4. 解析得到整數 -42 。
  5. 由於 "-42" 在範圍 [-231, 231 - 1] 內,最終結果為 -42 。

示例3:
輸⼊:s = "4193 with words"
輸出:4193
解釋:

  1. 第 1 步:"4193 with words"(當前沒有讀⼊字符,因為沒有前導空格)
  2. 第 2 步:"4193 with words"(當前沒有讀⼊字符,因為這⾥不存在 '-' 或者 '+')
  3. 第 3 步:"4193 with words"(讀⼊ "4193";由於下⼀個字符不是⼀個數字,所以讀⼊停⽌)
  4. 解析得到整數 4193 。
  5. 由於 "4193" 在範圍 [-231, 231 - 1] 內,最終結果為 4193 。

示例4:
輸⼊:s = "words and 987"
輸出:0
解釋:

  1. 第 1 步:"words and 987"(當前沒有讀⼊字符,因為沒有前導空格)
  2. 第 2 步:"words and 987"(當前沒有讀⼊字符,因為這⾥不存在 '-' 或者 '+')
  3. 第 3 步:"words and 987"(由於當前字符 'w' 不是⼀個數字,所以讀⼊停⽌)
  4. 解析得到整數 0 ,因為沒有讀⼊任何數字。
  5. 由於 0 在範圍 [-231, 231 - 1] 內,最終結果為 0 。

示例5:
輸⼊:s = "-91283472332"
輸出:-2147483648
解釋:

  1. 第 1 步:"-91283472332"(當前沒有讀⼊字符,因為沒有前導空格)
  2. 第 2 步:"-91283472332"(讀⼊ '-' 字符,所以結果應該是負數)
  3. 第 3 步:"-91283472332"(讀⼊ "91283472332")
  4. 解析得到整數 -91283472332 。
  5. 由於 -91283472332 ⼩於範圍 [-231, 231 - 1] 的下界,最終結果被截斷為 -231 = -2147483648

提示:

  • 0 <= s.length <= 200
  • s 由英⽂字⺟(⼤寫和⼩寫)、數字(0-9)、' '、'+'、'-' 和 '.' 組成

思路與解答

基礎遍歷法

這道題⽬看起來很⻓,但是實際上邏輯很清晰,就是將字符串解析成為數字,⾥⾯有⼏個特殊的則:

  1. 前⾯的空格去掉,不讀取
  2. 接下來的字符必須是數字,“ + ”號或者“ - ”號
    1. 如果是“ + ”號或者“ - ”號,將符號記錄下來
    2. 沒有符號默認是“ + ”號,正數。
  3. 接下來的字符必須是數字,遇到其他字符會直接結束
  4. 需要考慮溢出的問題

在將字符串轉換成數字的時候,⽤下⾯這句核⼼代碼:

sum = sum * 10 + (str.charAt(i) - '0');

但是在這個過程中,我們依然需要考慮數字溢出的問題,針對這種情況,我們可以在加和之前判斷,針對⼤於0的情況,如果⼤於最⼤值整除10,或者等於最⼤值整除10,但是個位數超過了,都直接返回0。

假設最⼤值是127,那麼sum如果⼤於12,肯定會超過,如果sum == 12,但是個位數⼤於7,乘以10相加,也肯定會超。

if (sum > Integer.MAX_VALUE/10 || (sum == Integer.MAX_VALUE / 10 &&
(str.charAt(i) - '0') > 7)) return 0;

對於⼩於0 的情況,假設最⼩值是-128 ,那麼sum 是數字部分 128 , 如果當前sum ⼤於 12 ,那麼就⼀定超出,或者sum == 12 ,但是個位數⼤於8 ,乘以10 ,相加也會⼤於128 ,不符合要求,所以直接返回0 。

if (sum < Integer.MIN_VALUE/10 || (sum == Integer.MIN_VALUE / 10 && x
(str.charAt(i) - '0') > 8)) return 0;

具體代碼實現:

public class Solution {
    public static int myAtoi(String str) {
        if (str == null) {
            return 0;
        }
        int i = 0;
        while (i < str.length() && str.charAt(i) == ' ') {
            i++;
        }
        if (i >= str.length() || (str.charAt(i) != '-' && str.charAt(i) != '+' && !((str.charAt(i) >= '0') &&
                (str.charAt(i) <= '9')))) {
            return 0;
        }
        int sign = 1;
        if (i < str.length() && (str.charAt(i) == '-' || i < str.length() &&
                str.charAt(i) == '+')) {
            sign = str.charAt(i) == '-' ? -1 : 1;
            i++;
        }
        int sum = 0;
        for (; i < str.length(); i++) {
            if (str.charAt(i) >= '0' && str.charAt(i) <= '9') {
                if (sign == 1) {
                    if (sum > Integer.MAX_VALUE / 10 || sum == Integer.MAX_VALUE / 10 && (str.charAt(i) - '0') > 7) {
                        return Integer.MAX_VALUE;
                    }
                } else {
                    if (sum > (Integer.MAX_VALUE) / 10 || sum ==
                        (Integer.MAX_VALUE) / 10 && (str.charAt(i) - '0') > 8) {
                        return Integer.MIN_VALUE;
                    }
                }
                sum = sum * 10 + (str.charAt(i) - '0');
            } else {
                return sum * sign;
            }
        }
        return sum * sign;
    }
}
  • 時間複雜度為 O(n)
  • 空間複雜度為 O(1)。

正則表達式

使用正則表達式來匹配數字模式,代碼更加簡潔

public class Solution {
    public int myAtoi(String s) {
        if (s == null) return 0;
        
        s = s.trim();
        if (s.length() == 0) return 0;
        
        // 使用正則表達式匹配數字模式:可選符號位+數字[3](@ref)
        Pattern pattern = Pattern.compile("^[+-]?\\d+");
        Matcher matcher = pattern.matcher(s);
        
        if (!matcher.find()) {
            return 0; // 沒有匹配到數字模式
        }
        
        String numStr = matcher.group();
        int sign = 1;
        int startIndex = 0;
        
        // 處理符號位
        if (numStr.charAt(0) == '+') {
            startIndex = 1;
        } else if (numStr.charAt(0) == '-') {
            sign = -1;
            startIndex = 1;
        }
        
        long result = 0; // 使用long防止轉換過程中溢出
        
        // 轉換數字部分
        for (int i = startIndex; i < numStr.length(); i++) {
            int digit = numStr.charAt(i) - '0';
            result = result * 10 + digit;
            
            // 檢查是否溢出int範圍
            if (sign == 1 && result > Integer.MAX_VALUE) {
                return Integer.MAX_VALUE;
            }
            if (sign == -1 && -result < Integer.MIN_VALUE) {
                return Integer.MIN_VALUE;
            }
        }
        
        return (int) result * sign;
    }
}
  • 時間複雜度:O(n),正則匹配和數字轉換都是線性時間
  • 空間複雜度:O(n),需要存儲匹配到的子字符串
user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.