前言

首先,正式庆祝这是我在知乎专栏写作的第 20 篇题解(这里的下标从 1 开始)。当然,我本地库存的题解,还要比发布出来的多一倍。

关键字:字符串,状态机

归航return:(Trivial) LeetCode 6—Z 字形变换​zhuanlan.zhihu.com

归航return:(Trivial) LeetCode 46—全排列​zhuanlan.zhihu.com


Problem

请你来实现一个 atoi 函数,使其能将字符串转换成整数。

首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:

  • 如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
  • 假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
  • 该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。

注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。

在任何情况下,若函数不能进行有效的转换时,请返回 0 。

提示:

  • 本题中的空白字符只包括空格字符 ' ' 。
  • 假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−2^31, 2^31 − 1]。如果数值超过这个范围,请返回 INT_MAX (2^31 − 1) 或 INT_MIN (−2^31) 。

示例 1:

输入: "42"
输出: 42

示例 2:

输入: "   -42"
输出: -42
解释: 第一个非空白字符为 '-', 它是一个负号。我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。

示例 3:

输入: "4193 with words"
输出: 4193
解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。

示例 4:

输入: "words and 987"
输出: 0
解释: 第一个非空字符是 'w', 但它不是数字或正、负号。因此无法执行有效的转换。

示例 5:

输入: "-91283472332"
输出: -2147483648
解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−2^31) 。

8. 字符串转换整数 (atoi) - 力扣(LeetCode)​leetcode-cn.com

Solution

这道题目也没有很 tricky 的东西,完全就是需要自己足够细心来处理问题。关于这个问题,我的思路是这样的:

(1)维护一个最终结果是负数还是非负数的 int 变量,和一个存储所有数字的 queue,容器的 instantiation 是 char 类型;

(2)逐个扫描字符串中的元素,直到字符串被扫描完毕,或者遇到了第一个一定不合法的字符(不是数字,空格,或者正负号);

(3)如果扫描过程中第一次遇到了数字,空格,或者正负号,那么意味着之后的合法字符必须全部是数字,因此将 queue 中插入一个 0,或者是这个数字本身,用来表明这个更高的合法性要求(使用 queue 非空作为是否需要使用这个合法性要求的条件),而且如果是负号,应该将上述的非负数变量 flag 记作 -1,之后将所有的数字加入队列中来;

if (numQueue.empty())

(4)得到所有数字之后,维护一个 string 类型,将 queue 中的数字字符变成数字字符串,这里需要将开头的 0 去掉,因此维护一个 bool 变量来标记是否遇到过非零的数;

(5)第(4)步中得到的 string 就是以字符串形式存储的要求的整数的绝对值,根据非负数和负数的情况分别判定是否可能溢出,如果溢出就返回极端值,否则就将这个 string 从左到右地转化为整数即可,这里还需要一个模拟人类比较两个非负整数大小的辅助函数:

bool isFormerNumericallyBiggerThanLatter(const string &s1,const string &s2);

综上所述,代码如下:

class Solution {public:int myAtoi(string str) {if (str.size() == 0)return 0;int res = 0;int isPositive = 1;queue<char>numQueue;for (int i = 0; i < str.size(); ++i){if (!mayBePossible(str[i])){break;}else{if (numQueue.empty()){if (str[i] == ' '){continue;}else if (str[i] == '-'){isPositive = -1;numQueue.push('0');}else if (str[i] == '+'){numQueue.push('0');}else if (isdigit(str[i])){numQueue.push(str[i]);}}else{if (!isdigit(str[i])){break;}elsenumQueue.push(str[i]);}}}bool isFirstNonZeroEmerged = 0;string resInString;while (!numQueue.empty()){if (isFirstNonZeroEmerged){resInString += numQueue.front();numQueue.pop();}else{if (numQueue.front() != '0'){isFirstNonZeroEmerged = 1;resInString += numQueue.front();}numQueue.pop();}}if (isPositive == 1 && isFormerNumericallyBiggerThanLatter(resInString, "2147483647"))return INT_MAX;if (isPositive==-1 && isFormerNumericallyBiggerThanLatter(resInString, "2147483648"))return INT_MIN;for (const char &ch:resInString){res = 10*res + isPositive*(ch-'0');}return res;}
private:bool mayBePossible(const char &ch){return (isdigit(ch) || ch == ' ' || ch == '-' || ch=='+');}bool isFormerNumericallyBiggerThanLatter(const string &s1, const string &s2){if (s1.size() != s2.size()){return s1.size() > s2.size();}for (int i = 0; i < s1.size(); ++i){if (s1[i] != s2[i])return s1[i] > s2[i];}return false;}
};

这个解法的耗时是 4ms,打败了 82.47% 的 C++ 提交。

在官方题解中还给出了一种使用状态机的思想写出来的代码,虽然耗时比我这种各种 if else 要长(20ms,打败了 8% 的 C++ 提交),而且使用了 long long 类型,但是可读性比我的明显要好,值得学习。

首先维护了一个 table 用来存储状态,分为四种:start 代表空格,signed 代表遇到了正负号,in_number 代表某个是数字,end 代表转化到了尾部状态了,容易观察到这几个状态的状态转移关系,结果在下方这个 unordered_map 中。和有些长度固定的 unordered_map 问题一样,这道题目也可以使用二维 int 数组来代替 unordered_map 来优化时间,但我就不狗尾续貂了,关键是学习这种思想。

复制代码如下:

class Automaton {string state = "start";//int state = 0;unordered_map<string, vector<string>> table = {{"start", {"start", "signed", "in_number", "end"}},{"signed", {"end", "end", "in_number", "end"}},{"in_number", {"end", "end", "in_number", "end"}},{"end", {"end", "end", "end", "end"}}};/*const int table[4][4] = {{0,1,2,3},{3,3,2,3},{3,3,2,3},{3,3,3,3}}; //use a 2-dimensional array to represent the unordered map in the official solution*/int get_col(char c) {if (isspace(c)) return 0;if (c == '+' or c == '-') return 1;if (isdigit(c)) return 2;return 3;}
public:int sign = 1;long long ans = 0;void get(char c) {state = table[state][get_col(c)];if (state == "in_number") {ans = ans * 10 + c - '0';ans = sign == 1 ? min(ans, (long long)INT_MAX) : min(ans, -(long long)INT_MIN);}else if (state == "signed")sign = c == '+' ? 1 : -1;}
};class Solution {public:int myAtoi(string str) {Automaton automaton;for (char c : str){automaton.get(c);}    return automaton.sign * automaton.ans;}
};

这个思路的 Java 实现:

class Solution {public int myAtoi(String str) {int curState = 0;int isPositive = 1;long res = 0;for (int i = 0; i < str.length(); ++i){char ch = str.charAt(i);curState = state[curState][getState(ch)];if (curState == 1){isPositive = (ch == '+') ? 1 : -1;}if (curState == 2){res *= 10L;res += ch-'0';if (res >= -(long)(Integer.MIN_VALUE))break;/*If the absolute value of result is more than -INT_MIN, the result must be overflowed.*/}if (curState == 3){break;}}res *= isPositive;if (res >= Integer.MAX_VALUE){return Integer.MAX_VALUE;}else if (res <= Integer.MIN_VALUE){return Integer.MIN_VALUE;}return res;}final private int [][] state = {{0,1,2,3},{3,3,2,3},{3,3,2,3},{3,3,3,3}};/* 0 for beginning, 1 for the sign(positive or negative),
2 for digits, 3 for terminating further input.*/private int getState(char ch){if (ch == ' '){return 0;}else if (ch == '+' || ch == '-'){return 1;}else if (isDigit(ch)){return 2;}return 3;}
}

和 C++ 语法不一样的几个点:

  • C++ 中求 string 的长度可以用 str.size() 或者 str.length(),但 Java 中必须使用 str.length()
  • C++ 中获得字符串某个位置的结果可以使用 str.operator[]() 函数或者 str.at() 函数,区别在于前者不加入越界检查,后者会强制进行越界检查,但 Java 仅仅支持 str.charAt() 函数,且越界检查是强制的;
  • C++ 遍历一个 string 可以使用 range-based for loop:char ch : str ,但 Java 不允许(我尝试这么做编译错误);
  • C++ 的int 类型最大值是 INT_MAX,而 Java 是 Integer.MAX_VALUE,C++ 中判定一个字符是否是数字可以直接 isdigit(ch)(包含在 <cctype> 这个头文件中),但 Java 的用法是 Character.isDigit(ch),前面的 Character 不可省略;
  • C++ 中允许 long 类型到 int 的隐式类型转换—当然更好的做法是:static_cast<int>(someLongVariable),但 Java 中必须直接指出这一点,Java 不做说明的情况下只允许 implicit type casting,向上转换,而不允许 implicit type conversion 向下转换。

EOF。

32位有符号整数_(Trivial)LeetCode 8—字符串转化为整数(atoi)相关推荐

  1. c++ 32位有符号的整数_【LeetCode】字符串分类字符串转换整数 (atoi)

    " 摘要:本文主要讲述LeetCode字符串分类字符串转换整数 (atoi)解法.主要内容如下: 题目 示例 解题 " 01 - 题目 请你来实现一个 atoi 函数,使其能将字符 ...

  2. python当用户输入的不是整数_当用户输入字符串而不是整数时,如何保护我的python代码?...

    请看一下我对您的代码所做的更改,如下所示:def add (x, y): return(x + y) def subtract(x, y): return(x - y) def multiply(x, ...

  3. 《剑指offer》-- 栈的压入与弹出序列、把字符串转化为整数、扑克牌顺子、孩子们的游戏(圆圈中最后剩下的数)

    一.栈的压入与弹出序列: 1.题目: 输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序. 假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序 ...

  4. 算法: 把字字符串转化为整数;

    算法: 把字字符串转化为整数: * @问题: 把字符串转化为整数* 题目描述* 将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返 ...

  5. 32位有符号整数_[LeetCode] 8. 字符串转换整数 (atoi)

    题目链接:https://leetcode-cn.com/problems/string-to-integer-atoi/ 题目描述: 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先 ...

  6. 32位有符号整数_008. 字符串转换整数 (atoi) | Leetcode题解

    点击上方"蓝色字体",选择"设为星标" 每天复习一道面试题,轻松拿大厂Offer~ 题目描述: 请你来实现一个 atoi 函数,使其能将字符串转换成整数. 首先 ...

  7. 给定一个32位有符号整数,将整数中的数字进行翻转

    给定一个32位有符号整数,将整数中的数字进行翻转 解题思路就是不断的求模,然后取余,然后注意溢出问题: 代码: #include<stdlib.h> #include<stdio.h ...

  8. c语言整形符号位_C语言中32位有符号整数如何定义

    展开全部 根据计算机系统.编译系统的不同,32位有符号整数的定义会略有差异,通常的做法32313133353236313431303231363533e59b9ee7ad943133343136363 ...

  9. 给定一个 32 位有符号整数,将整数中的数字进行反转。

    示例: 例如:给定数"456",需返回"654",给定"-876",则需返回"-678" 注意: 假设我们的环境只能存储 ...

  10. Verilog除法器(32位无符号+带符号)

    32位无符号除法器设计 恢复余数法: 恢复余数除法的基本思路是从"部分余数"中减去除数,如果结果为负(不够减),则恢复原来的部分余数,商0. 寄存器使用: reg_r 存放被除数a ...

最新文章

  1. web App libraries跟referenced libraries的一些问题
  2. 三星android获取root权限,三星G9250(S6 Edge公开版全网通 Android 5.1)获取ROOT权限详解教程...
  3. R语言临床预测模型的评价指标与验证指标实战:综合判别改善指数IDI(Integrated Discrimination Improvement, IDI)
  4. python画曲线图例-Python画各种图
  5. 计算机考研只有数据结构,【择校必看】十三所计算机专业课只考数据结构的985院校!...
  6. 光谱分类算法 matlab,Matlab K-means聚类算法对多光谱遥感图像进行分类(一)
  7. InfoPath开发经验小节
  8. 开放、普惠、高性能-SLS时序存储助力打造企业级全方位监控方案
  9. (28)FPGA计数器设计(软核实现)
  10. 解决:Conversion to Dalvik format failed: Unable to execute dex: null
  11. 集合阿里云、达摩院、平头哥相关技术的HaaS,官宣出书啦
  12. IDEA设置Maven组合命令一键编译打包发布
  13. 【数据结构】线性表之链式线性表
  14. C++ 字符编码转换之UTF-8/UTF-16/UTF-32
  15. IAR for STM8介绍、下载、安装与注册
  16. win10如何显示文件后缀
  17. 【SVM分类】基于遗传算法优化支持向量机实现葡萄酒分类附matlab代码
  18. 计算机技术数字影音,技能大赛数字影音后期制作技术赛项规程.pdf
  19. 【Python机器学习及实践】实战篇:泰坦尼克号罹难乘客预测
  20. c语言车队,狂野飙车8车队中c车的详细属性介绍

热门文章

  1. Facebook股价周四大涨15.5% 市值超亚马逊
  2. 工具型产品的设计感想
  3. bgp属性分析--ORIGIN
  4. hive不在同一台机 hue_【Impala篇】---Hue从初始到安装应用
  5. 07.electron-(渲染进程和主进程)通信
  6. ABP vnext 未通过Token访问接口时显示HTML,调整为跳转403和提示
  7. .net core 定时任务
  8. Layui第三方扩展LAY_EXCEL导出数据表格的数据
  9. CSDN MarkDown编辑器的使用(原内容)
  10. python微软产品一般都一个25位的序列号_Python易错点6