有限状态机思想 在刷Leetcode的时候发现又一部分字符串转化的问题可以使用有限状态机很好的解决,所以记录一下,方便下次遇到这种题型进行编写。
字符串转换整数(atoi) 题目描述 请你来实现一个atoi函数,使其能将字符串转换成整数。
首先,该函数会根据需要丢弃无用的开头空格字符,直到寻找到第一个非空格的字符为止。接下来的转化规则如下:
如果第一个非空字符为正或者负号时,则将该符号与之后面尽可能多的连续数字字符组合起来,形成一个有符号整数。
假如第一个非空字符是数字,则直接将其与之后连续的数字字符组合起来,形成一个整数。
该字符串在有效的整数部分之后也可能会存在多余的字符,那么这些字符可以被忽略,它们对函数不应该造成影响。
注意:假如该字符串中的第一个非空格字符不是一个有效整数字符、字符串为空或字符串仅包含空白字符时,则你的函数不需要进行转换,即无法进行有效转换。
在任何情况下,若函数不能进行有效的转换时,请返回 0 。
提示:
本题中的空白字符只包括空格字符 ‘ ‘ 。
假设我们的环境只能存储 32 位大小的有符号整数,那么其数值范围为 [−231, 231 − 1]。如果数值超过这个范围,请返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
示例 2:
1 2 3 4 输入: " -42" 输出: -42 解释: 第一个非空白字符为 '-', 它是一个负号。 我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
1 2 3 输入: "4193 with words" 输出: 4193 解释: 转换截止于数字 '3' ,因为它的下一个字符不为数字。
示例 4:
1 2 3 4 输入: "words and 987" 输出: 0 解释: 第一个非空字符是 'w', 但它不是数字或正、负号。 因此无法执行有效的转换。
示例 5:
1 2 3 4 输入: "-91283472332" 输出: -2147483648 解释: 数字 "-91283472332" 超过 32 位有符号整数范围。 因此返回 INT_MIN (−231) 。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/string-to-integer-atoi 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码 方法一: 在剑指offer上有这一题,上面提供的方法是使用类似于分类的方法、
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Solution { public int myAtoi (String str) { if (str==null || str.length()<=0 ) { return 0 ; } long res = 0 ; String s = str.trim(); if (s.length()>0 ) { char [] chars = s.toCharArray(); int start = 0 ; boolean isPositive =true ; if (chars[0 ]=='+' ) { isPositive =true ; start = 1 ; }else if (chars[0 ]=='-' ) { isPositive =false ; start = 1 ; } for (int i = start; i < chars.length; i++) { if (chars[i]>='0' && chars[i]<='9' ) { res = res*10 +chars[i]-'0' ; if (res>Integer.MAX_VALUE) { return isPositive?Integer.MAX_VALUE :Integer.MIN_VALUE; } } else { break ; } } if (!isPositive) { res = 0 -res; } } return (int )res; } }
这种方法,比较好,理解起来也比较简单
方法二: 使用状态机进行编写。字符串处理的题目往往涉及复杂的流程以及条件情况,如果直接上手写程序,一不小心就会写出极其臃肿的代码。
因此,为了有条理地分析每个输入字符的处理方法,我们可以使用自动机这个概念:
我们的程序在每个时刻有一个状态 s,每次从序列中输入一个字符c,并根据字符 c 转移到下一个状态 s'。这样,我们只需要建立一个覆盖所有情况的从 s 与 c 映射到 s' 的表格即可解决题目中的问题。
首先我们可以确定输入有:
空格’ ‘
符号:+-号
数字:0,1,2,3,4,5,6,7,8,9
其他
下面是官方题解给出的自动机状态图
我们也可以用下面的表格来表示这个自动机:
‘ ‘
+/-
number
other
start
start
signed
in_number
end
signed
end
end
in_number
end
in_number
end
end
in_number
end
end
end
end
end
end
接下来编程部分就非常简单了:我们只需要把上面这个状态转换表抄进代码即可。
另外自动机也需要记录当前已经输入的数字,只要在 s’ 为 in_number 时,更新我们输入的数字,即可最终得到输入的数字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Automaton { string state = "start" ; 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" }} }; 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; } };
原地址:https://leetcode-cn.com/problems/string-to-integer-atoi/solution/zi-fu-chuan-zhuan-huan-zheng-shu-atoi-by-leetcode-/ 可以有限状态机的解法非常巧妙,对于条件多、状态多的情况来说无疑是最好的解法。
有效数字 题目描述 验证给定的字符串是否可以解释为十进制数字。
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 "0" => true " 0.1 " => true "abc" => false "1 a" => false "2e10" => true " -90e3 " => true " 1e" => false "e3" => false " 6e-1" => true " 99e2.5 " => false "53.5e93" => true " --6 " => false "-+3" => false "95a54e53" => false
说明: 我们有意将问题陈述地比较模糊。在实现代码之前,你应当事先思考所有可能的情况。这里给出一份可能存在于有效十进制数字中的字符列表:
数字 0-9
指数 - “e”
正/负号 - “+”/“-“
小数点 - “.”
当然,在输入中,这些字符的上下文也很重要。
来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems/valid-number 著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
代码 方法一: 使用状态机进行编写。根据题目描述我们知道输入有
数字 0-9
指数 - “e”
正/负号 - “+”/“-“
小数点 - “.”
然后可以画一下状态图(来自https://leetcode-cn.com/problems/valid-number/solution/biao-qu-dong-fa-by-user8973/):
接着跟上面一样画出表格
state
blank
+/-
0-9
.
e
other
0
0
1
6
2
-1
-1
1
-1
-1
6
2
-1
-1
2
-1
-1
3
-1
-1
-1
3
8
-1
3
-1
4
-1
4
-1
7
5
-1
-1
-1
5
8
-1
5
-1
-1
-1
6
8
-1
6
3
4
-1
7
-1
-1
5
-1
-1
-1
8
8
-1
-1
-1
-1
-1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Solution { public int make (char c) { switch (c) { case ' ' : return 0 ; case '+' : case '-' : return 1 ; case '.' : return 3 ; case 'e' : return 4 ; default : if (c >= 48 && c <= 57 ) return 2 ; } return -1 ; } public boolean isNumber (String s) { int state = 0 ; int finals = 0b101101000 ; int [][] transfer = new int [][]{{ 0 , 1 , 6 , 2 ,-1 }, {-1 ,-1 , 6 , 2 ,-1 }, {-1 ,-1 , 3 ,-1 ,-1 }, { 8 ,-1 , 3 ,-1 , 4 }, {-1 , 7 , 5 ,-1 ,-1 }, { 8 ,-1 , 5 ,-1 ,-1 }, { 8 ,-1 , 6 , 3 , 4 }, {-1 ,-1 , 5 ,-1 ,-1 }, { 8 ,-1 ,-1 ,-1 ,-1 }}; char [] ss = s.toCharArray(); for (int i=0 ; i < ss.length; ++i) { int id = make(ss[i]); if (id < 0 ) return false ; state = transfer[state][id]; if (state < 0 ) return false ; } return (finals & (1 << state)) > 0 ; } }
来自于:https://leetcode-cn.com/problems/valid-number/solution/biao-qu-dong-fa-by-user8973/
方法二: 责任链
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 interface NumberValidate { boolean validate (String s) ; } abstract class NumberValidateTemplate implements NumberValidate { public boolean validate (String s) { if (checkStringEmpty(s)) { return false ; } s = checkAndProcessHeader(s); if (s.length() == 0 ) { return false ; } return doValidate(s); } private boolean checkStringEmpty (String s) { if (s.equals("" )) { return true ; } return false ; } private String checkAndProcessHeader (String value) { value = value.trim(); if (value.startsWith("+" ) || value.startsWith("-" )) { value = value.substring(1 ); } return value; } protected abstract boolean doValidate (String s) ; } class IntegerValidate extends NumberValidateTemplate { protected boolean doValidate (String integer) { for (int i = 0 ; i < integer.length(); i++) { if (Character.isDigit(integer.charAt(i)) == false ) { return false ; } } return true ; } } class SienceFormatValidate extends NumberValidateTemplate { protected boolean doValidate (String s) { s = s.toLowerCase(); int pos = s.indexOf("e" ); if (pos == -1 ) { return false ; } if (s.length() == 1 ) { return false ; } String first = s.substring(0 , pos); String second = s.substring(pos+1 , s.length()); if (validatePartBeforeE(first) == false || validatePartAfterE(second) == false ) { return false ; } return true ; } private boolean validatePartBeforeE (String first) { if (first.equals("" ) == true ) { return false ; } if (checkHeadAndEndForSpace(first) == false ) { return false ; } NumberValidate integerValidate = new IntegerValidate(); NumberValidate floatValidate = new FloatValidate(); if (integerValidate.validate(first) == false && floatValidate.validate(first) == false ) { return false ; } return true ; } private boolean checkHeadAndEndForSpace (String part) { if (part.startsWith(" " ) || part.endsWith(" " )) { return false ; } return true ; } private boolean validatePartAfterE (String second) { if (second.equals("" ) == true ) { return false ; } if (checkHeadAndEndForSpace(second) == false ) { return false ; } NumberValidate integerValidate = new IntegerValidate(); if (integerValidate.validate(second) == false ) { return false ; } return true ; } } class FloatValidate extends NumberValidateTemplate { protected boolean doValidate (String floatVal) { int pos = floatVal.indexOf("." ); if (pos == -1 ) { return false ; } if (floatVal.length() == 1 ) { return false ; } NumberValidate nv = new IntegerValidate(); String first = floatVal.substring(0 , pos); String second = floatVal.substring(pos + 1 , floatVal.length()); if (checkFirstPart(first) == true && checkFirstPart(second) == true ) { return true ; } return false ; } private boolean checkFirstPart (String first) { if (first.equals("" ) == false && checkPart(first) == false ) { return false ; } return true ; } private boolean checkPart (String part) { if (Character.isDigit(part.charAt(0 )) == false || Character.isDigit(part.charAt(part.length() - 1 )) == false ) { return false ; } NumberValidate nv = new IntegerValidate(); if (nv.validate(part) == false ) { return false ; } return true ; } } class NumberValidator implements NumberValidate { private ArrayList<NumberValidate> validators = new ArrayList<NumberValidate>(); public NumberValidator () { addValidators(); } private void addValidators () { NumberValidate nv = new IntegerValidate(); validators.add(nv); nv = new FloatValidate(); validators.add(nv); nv = new HexValidate(); validators.add(nv); nv = new SienceFormatValidate(); validators.add(nv); } @Override public boolean validate (String s) { for (NumberValidate nv : validators) { if (nv.validate(s) == true ) { return true ; } } return false ; } } public boolean isNumber (String s) { NumberValidate nv = new NumberValidator(); return nv.validate(s); }
利用责任链的设计模式,会使得写出的算法扩展性以及维护性更高。这里用到的思想就是,每个类只判断一种类型。比如判断是否是正数的类,判断是否是小数的类,判断是否是科学计数法的类,这样每个类只关心自己的部分,出了问题很好排查,而且互不影响。 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
具体可以参考链接:https://leetcode-cn.com/problems/valid-number/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by-1-4/