/**
 * @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中的每个字符,都有可能是以下的四种类型中的一种:

  1. 空格字符' '(Space)
  2. 正负号+和-(Sign)
  3. 字符串型的数值(Number)
  4. 除以上三种情况外的任何情况(Other)

阶段分析
如果想要将字符串转换为整数,那么必然会经历这四个有序的阶段:

  1. 开始转换(start)
  2. 判断正负(signed)
  3. 生成数值(in_number)
  4. 结束转换(end)

梳理为表格形式

javascript整形转字符串 js字符串转换为整形_易错点

 

javascript整形转字符串 js字符串转换为整形_javascript 整形转字符串_02

 

 

 解决的问题:字符串转换整数 (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;
    }
};