
/** * @param {string} str * @return {number} */ var myAtoi = function(str) { // 自動機類 class Automaton{ constructor() { // 執行階段,默認處於開始執行階段 this.state = 'start'; // 正負符號,默認是正數 this.sign = 1; // 數值,默認是0 this.answer = 0; /* 關鍵點: 狀態和執行階段的對應表 含義如下: [執行階段, [空格, 正負, 數值, 其他]] */ this.map = new Map([ ['start', ['start', 'signed', 'in_number', 'end']], ['signed', ['end', 'end', 'in_number', 'end']], ['in_number', ['end', 'end', 'in_number', 'end']], ['end', ['end', 'end', 'end', 'end']] ]) } // 獲取狀態的索引 getIndex(char) { if (char === ' ') { // 空格判斷 return 0; } else if (char === '-' || char === '+') { // 正負判斷 return 1; } else if (typeof Number(char) === 'number' && !isNaN(char)) { // 數值判斷 return 2; } else { // 其他情況 return 3; } } /* 關鍵點: 字符轉換執行函數 */ get(char) { /* 易錯點: 每次傳入字符時,都要變更自動機的執行階段 */ this.state = this.map.get(this.state)[this.getIndex(char)]; if(this.state === 'in_number') { /* 小技巧: 在JS中,對字符串類型進行減法操作,可以將得到一個數值型(Number)的值 易錯點: 本處需要利用括號來提高四則運算的優先級 */ this.answer = this.answer * 10 + (char - 0); /* 易錯點: 在進行負數比較時,需要將INT_MIN變為正數 */ this.answer = this.sign === 1 ? Math.min(this.answer, Math.pow(2, 31) - 1) : Math.min(this.answer, -Math.pow(-2, 31)); } else if (this.state === 'signed') { /* 優化點: 對於一個整數來說,非正即負, 所以正負號的判斷,只需要一次。 故,可以降低其判斷的優先級 */ this.sign = char === '+' ? 1 : -1; } } } // 生成自動機實例 let automaton = new Automaton(); // 遍歷每個字符 for(let char of str) { // 依次進行轉換 automaton.get(char); } // 返回值,整數 = 正負 * 數值 return automaton.sign * automaton.answer; };
自動機
我們的程序在每個時刻有一個狀態s,每次從序列中輸入一個字符c,並根據字符c 轉移到下一個狀態s'。
這樣,我們只需要建立一個覆蓋所有情況的從s與c映射到s'的表格即可解決題目中的問題。
來源:力扣(LeetCode)
字符串str中的每個字符,都有可能是以下的四種類型中的一種:
- 空格字符' '(Space)
- 正負號+和-(Sign)
- 字符串型的數值(Number)
- 除以上三種情況外的任何情況(Other)
階段分析
如果想要將字符串轉換為整數,那么必然會經歷這四個有序的階段:
- 開始轉換(start)
- 判斷正負(signed)
- 生成數值(in_number)
- 結束轉換(end)
梳理為表格形式
解決的問題:字符串轉換整數 (atoi)
可以想到Javascript 的 parseInt(),使用這個API,進行嘗試。
parseInt(string, radix):
string:要被解析的值。如果參數不是一個字符串,則將其轉換為字符串。字符串開頭的空白符將會被忽略。
radix(可選):需要轉換的進制,介於 2 到 36。
返回值: 如果被解析參數的第一個字符無法被轉化成數值類型,則返回NaN。
- 無視開頭空格(√)
- 返回有符號整數(√)
- 無視整數部分后的字符(√)
- 范圍在
32
位內(含)(x) - 其他情況返回
0
(x)
需要注意:
在使用parseInt(string, radix)這一API時,如果不傳入radix參數,會有兩種特殊情況:
如果字符串 string 以"0x"或者"0X"開頭, 則基數是16 (16進制).
如果字符串 string 以"0"開頭, 基數是8(八進制)或者10(十進制),那么具體是哪個基數,取決與ECMAScript的版本。
/** * @param {string} s * @return {number} */ var myAtoi = function(s) { const number = parseInt(s, 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; } };