【前端er每日一算法题】Leetcode 字符串转换整数 (atoi)

121 阅读2分钟

题目

请你来实现一个 myAtoi(string s) 函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi 函数) leetcode链接

思路

直接写:

  1. 跳过前导空白符‘’
  2. 判断首字母是否是‘+’、‘-’,记录sign
  3. 如果是数字,则进行计算
  4. 判断是否大于最大值或者小于最小值

惭愧的是这个也写了很多遍才对,面向bug编程==

但是看了答案发现,我去,竟然用了自动状态机,我太low了,还没写过自动状态机,之后要补一个

解答

算法1:普通算法

var myAtoi = function(s) {
    let reg = /[0-9]/
    let result = 0
    const max = Math.pow(2, 31) - 1
    const min = Math.pow(-2, 31)
    let j = 0
    let sign = 1
    while (j < s.length && s[j]== ' ') {
        j++
    }
    for (let i = j; i < s.length; i++) {
        let val = s[i]
        if (i == j && val == '+') {
            continue
        }
        if (i == j && val == '-') {
            sign = -1
            continue
        }
        val = parseInt(val, 10)
        if (!reg.test(val)) {
            return result
        }
        result = result * 10 + sign * val
        if (result < min) {
            return min
        }
        if (result > max) {
            return max
        }
    }
    return result
};

解答时遇到的问题:

  1. 指数求解api:Math.pow();忘记了,还查了查 Math.pow(2, 31) - 1;Math.pow(-2, 31)
  2. 一开始记录正负,用了flag,其实直接用sign记录1,-1就可以
  3. 优先把前导符过滤掉,否则会出现+-123 case失败的情况

算法2: 自动状态机

占位。。

最后,今天让我们看看chatgpt的解答:咦,它写的简单解法,没有自动状态机

image.png

代码cp如下:

function myAtoi(s) {
  const INT_MAX = Math.pow(2, 31) - 1; // 32位有符号整数的最大值
  const INT_MIN = Math.pow(-2, 31); // 32位有符号整数的最小值

  let i = 0;
  let sign = 1; // 符号,默认为正数
  let result = 0;

  // 跳过前面的空白字符
  while (i < s.length && s[i] === ' ') {
    i++;
  }

  // 处理符号位
  if (i < s.length && (s[i] === '-' || s[i] === '+')) {
    sign = s[i] === '-' ? -1 : 1;
    i++;
  }

  // 处理数字字符
  while (i < s.length && s[i] >= '0' && s[i] <= '9') {
    const digit = parseInt(s[i]);

    // 检查是否溢出
    if (result > Math.floor(INT_MAX / 10) || (result === Math.floor(INT_MAX / 10) && digit > 7)) {
      return sign === 1 ? INT_MAX : INT_MIN;
    }

    result = result * 10 + digit;
    i++;
  }

  // 返回结果
  return result * sign;
}

image.png

附代码:

function myAtoi(s) {
    // 定义状态常量
    const State = {
        START: 0,
        SIGN: 1,
        NUM: 2,
        END: 3
    };
    
    // 初始化状态和结果
    let state = State.START;
    let result = 0;
    let sign = 1;
    
    // 定义状态转换表
    const stateTable = [
        [State.START, State.SIGN, State.NUM, State.END], // 状态 START 的转换表
        [State.END, State.END, State.NUM, State.END], // 状态 SIGN 的转换表
        [State.END, State.END, State.NUM, State.END], // 状态 NUM 的转换表
        [State.END, State.END, State.END, State.END] // 状态 END 的转换表
    ];
    
    // 迭代字符串
    for (let i = 0; i < s.length; i++) {
        const char = s[i];
        let col;
        
        // 确定字符属于哪一列
        if (char === ' ') {
            col = 0; // 空格
        } else if (char === '-' || char === '+') {
            col = 1; // 符号
        } else if (char >= '0' && char <= '9') {
            col = 2; // 数字
        } else {
            col = 3; // 其他字符
        }
        
        // 获取下一状态
        state = stateTable[state][col];
        
        // 检查状态
        if (state === State.START || state === State.SIGN) {
            continue; // 继续处理下一个字符
        } else if (state === State.NUM) {
            // 将数字字符转换为数字,并累加到结果
            result = result * 10 + parseInt(char);
            
            // 检查是否溢出
            if (result * sign > Math.pow(2, 31) - 1) {
                return Math.pow(2, 31) - 1;
            } else if (result * sign < -Math.pow(2, 31)) {
                return -Math.pow(2, 31);
            }
        } else {
            break; // 遇到无效字符,退出循环
        }
    }
    
    return result * sign;
}