把字符串转换成整数(atoi):最直观的想法是,从字符串高位向低位遍历,然后逐个取字符串元素,先将字符转换为整型,再利用数位关系将其转换为数值。在纯数字的情况下,当然可以像这样做,但是本题中含有非法字符,且明确说明,在若干空格后,可能会存在符号,接着出现的一连串数字才是转换为数值的重要部分,如果后面再出现非法字符需要被舍弃。也就是说,字符串1234hello转换为数字则为1234,而字符串hello1234转换为数字是为0,即其是非法的,那么我们就不能从后向前遍历字符串,而应该从前向后遍历字符串。(试错)
idea:使用index标记字符串下标,其初始化为0;使用flag标记正负数,其true表示正数而false表示负数;使用hasNum标记是否已经碰到过数字,其true表示碰到过而false表示没碰到;使用res标记结果,其初始为0;具体做法如下:首先去掉前导空格,然后标记正负数,接着遍历剩余字符:如果遇到空格,则判断是否碰到过数字,如果碰到过则直接break,因为题目中说明是符号后一连串的整数,例如字符串+0 1234,其转换为数字应该是0,反之则直接跳过空格;如果遇到数字,则标记碰到过数字,然后进行越界处理,接着如果没越界则继续计算数值;如果遇到其他非法字符,则直接break;最后根据flag标记的正负数情况来处理结果res,再返回res即可。
// 处理越界 可以学习一下越界处理 if(res>INT_MAX/10||(res==INT_MAX/10 &&(s[index]-'0')>INT_MAX%10)) return flag==true?INT_MAX:INT_MIN;
int StrToInt(string s) {
// 字符串长度
int n=s.size();
// 字符串下标
int index=0;
// 标记正负数 true是正数 false是负数
bool flag=true;
// 标记记录过数字
bool hasNum=false;
// 记录结果
int res=0;
// 去除前导空格
while(s[index]==' ')
index++;
// 标记负数
if(s[index]=='-')
{
flag=false;
index++;
}
// 正数 默认也是正数
else if(s[index]=='+')
{
index++;
}
// 遍历剩余字符
while(index<n)
{
// 去除空格
if(s[index]==' ')
{
// + 0 1234
if(hasNum)
break;
else
index++;
}
// 数字 0-9
else if(s[index]>='0'&&s[index]<='9')
{
// 标记出现数字
hasNum=true;
// 处理越界
if(res>INT_MAX/10||(res==INT_MAX/10 &&(s[index]-'0')>INT_MAX%10))
return flag==true?INT_MAX:INT_MIN;
res=res*10+(s[index]-'0');
index++;
}
// 非法字符
else
break;
}
// 负数
if(flag==false)
res=-res;
return res;
}
优化:状态机模型。我们知道,根据上述转换规则来写的话,代码会出现很多判断条件,从而显得十分臃肿。其实,一般涉及到字符串的转换时,可以考虑状态机的解法。有限状态机指的是有限个状态以及这些状态之间的转移,其中转移是由当前状态以及条件得到下一个状态,所以我们首先要考虑有哪几个状态以及有哪些条件,再根据状态个数m和条件个数n绘制出大小为m*n的状态转移矩阵。以该题为例:字符类型无非就是空格、符号+/-、数字0-9、以及其他非法字符;状态无非就是初始状态start、符号位sign、数值number、以及结束end;其状态转移图以及状态转移表如下。
start | start | sign | number | end |
sign | sign | end | number | end |
number | end | end | number | end |
end | end | end | end | end |
idea:我们可以将上述四个状态映射为数字0、1、2、3,然后使用一个常数矩阵来存储状态转移,接着从头到尾遍历字符串,根据当前的字符类型,进入相应的状态,同时判断是否超过int上下界。
// 其中行表示当前状态 列分别表示遇到空格、符号、数字、非法字符相应的转换状态
vector<vector<int>> states={
{0,1,2,3},
{1,3,2,3},
{3,3,2,3},
{3,3,3,3} // 遇到非法字符直接退出循环故该行可省略
};
int StrToInt(string s)
{
// 其中行表示当前状态 列分别表示遇到空格、符号、数字、非法字符相应的转换状态
vector<vector<int>> states={
{0,1,2,3},
{1,3,2,3},
{3,3,2,3}
};
// 存储结果
int res=0;
// 标记正负数
bool flag=true;
// 初始状态为0
int state=0;
// 字符串长度
int n=s.size();
// 字符串当前元素
char ch;
// 从前向后遍历字符串
for(int i=0;i<n;i++)
{
// 当前元素
ch=s[i];
// 遇到空格
if(ch==' ')
state=states[state][0];
// 遇到符号
else if(ch=='+'||ch=='-')
{
state=states[state][1];
// 第一次遇到符号
if(state==1)
flag=(ch=='-')?false:true;
// 第二次遇到符号
else
break;
}
// 遇到数字
else if(ch>='0'&&ch<='9')
state=states[state][2];
// 遇到非法字符
else
break;
// 非法状态
if(state==3)
break;
// 计算数值
if(state==2)
{
// 溢出处理
if(res>INT_MAX/10||(res==INT_MAX/10 &&(ch-'0')>INT_MAX%10))
return flag==true?INT_MAX:INT_MIN;
// 计算数值
res=res*10+(ch-'0');
}
}
// 根据flag返回结果
return flag==true?res:-res;
}



京公网安备 11010502036488号