【剑指offer】64.表示数值的字符串
总目录:
1.问题描述
请实现一个函数用来判断字符串str是否表示数值(包括科学计数法的数字,小数和整数)。
科学计数法的数字(按顺序)可以分成以下几个部分:
1.若干空格
2.一个整数或者小数
3.(可选)一个 'e' 或 'E' ,后面跟着一个整数(可正可负)
4.若干空格
小数(按顺序)可以分成以下几个部分:
1.若干空格
2.(可选)一个符号字符('+' 或 '-')
3. 可能是以下描述格式之一:
3.1 至少一位数字,后面跟着一个点 '.'
3.2 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
3.3 一个点 '.' ,后面跟着至少一位数字
4.若干空格
整数(按顺序)可以分成以下几个部分:
1.若干空格
2.(可选)一个符号字符('+' 或 '-')
2.(可选)一个符号字符('+' 或 '-')
3. 至少一位数字
4.若干空格
例如,字符串["+100","5e2","-123","3.1416","-1E-16"]都表示数值。
但是["12e","1a3.14","1.2.3","+-5","12e+4.3"]都不是数值。
输入:"123.45e+6"返回值:true
输入:"1.2.3"返回值:false
输入:"."返回值:false
输入:" .2 "返回值:true
2.问题分析
难倒不是很难,就是边界条件角度,需要要严格审题
只允许空格在首和尾连续出现。
不允许除数字、正负号、e/E、小数点、空格之外的符号。
校验是否是科学计数法时,只允许有1个e/E,然后可以拆解为对e/E左右两侧分别进行合法检查,左侧允许为小数和带符号的整数,右边只允许为不带符号的整数;
校验是否是小数时,只允许有1个小数点,可以拆解为对小数点左右两侧分别进行合法化检查,左侧允许为空或带符号的整数,右侧允许为空或不带符号的整数,但同时最多允许一侧为空;
校验是否为整数时,仅允许第一个字符为正负符号,其他字符必须为数字。
1暴力迭代
3.代码实例
暴力迭代
1 class Solution { 2 public: 3 //常量特殊字符 4 const char dot = '.'; 5 const char eClass = 'e', EClass = 'E'; 6 const char empSpace = ' '; 7 const char posFlag = '+', negFlag = '-'; 8 9 //非空区域 10 int startPos = -1, endPos = -1; 11 12 //主函数 13 bool isNumeric(string str) { 14 int dataLen = str.length(); 15 if (dataLen <= 0) { 16 return false; 17 } 18 19 //裁剪掉前后空格 20 TrimEmpty(str); 21 if (startPos < 0 || endPos < 0) { 22 return false; 23 } 24 25 //是否有非法字符 26 bool hasIlligle = hasIlligleChar(str, startPos, endPos); 27 if (hasIlligle) { 28 return false; 29 } 30 31 bool isMatch = false; 32 bool hasEClass = hasEClassChar(str, startPos, endPos); 33 if (hasEClass) { 34 //是否是科学计数 35 isMatch = isSciNum(str, startPos, endPos); 36 if (isMatch) { 37 return isMatch; 38 } 39 } else { 40 bool hasDot = hasDotChar(str, startPos, endPos); 41 if (hasDot) { 42 //是否是小数 43 isMatch = isFloat(str, startPos, endPos); 44 if (isMatch) { 45 return isMatch; 46 } 47 } else { 48 //是否是整数 49 isMatch = isSignedInteger(str, startPos, endPos); 50 if (isMatch) { 51 return isMatch; 52 } 53 } 54 } 55 56 return false; 57 } 58 59 //获取非空部分 60 void TrimEmpty(const string& str) { 61 int dataLen = str.length(); 62 for (int i = 0; i < dataLen; i++) { 63 //不为空 64 if (str[i] != empSpace) { 65 //只记录第一个非空位置 66 if (startPos < 0) { 67 startPos = i; 68 } 69 70 //如果是最后一个字符 71 if (i == dataLen - 1) { 72 endPos = i; 73 } 74 } else { //为空 75 //在已经找到start的情况下,记录第一次遇到空格的位置 76 if (startPos >= 0 && endPos < 0) { 77 endPos = i - 1;//记录最后一个非空的位置 78 //在已经找到endPos的情况下,查看后面的是否都是空 79 for (i++; i < dataLen; i++) { 80 //又遇到非空 81 if (str[i] != empSpace) { 82 endPos = -1; 83 return; 84 } 85 } 86 } 87 } 88 } 89 } 90 91 //检查一个char是否是数字 92 bool isNumChar(const char charVal) { 93 return charVal >= '0' && charVal <= '9'; 94 } 95 96 bool hasIlligleChar(const string& str, const int start, const int end) { 97 for (int i = startPos; i <= endPos; i++) { 98 //shuzi 99 if (isNumChar(str[i])) { 100 continue; 101 } 102 //正负号 103 if (str[i] == posFlag || str[i] == negFlag) { 104 continue; 105 } 106 //小数点 107 if (str[i] == dot) { 108 continue; 109 } 110 //指数 111 if (str[i] == eClass || str[i] == EClass) { 112 continue; 113 } 114 } 115 116 return false; 117 } 118 119 bool hasEClassChar(const string& str, const int start, const int end) { 120 for (int i = start; i <= end; i++) { 121 //指数 122 if (str[i] == eClass || str[i] == EClass) { 123 return true;; 124 } 125 } 126 127 return false; 128 } 129 130 bool hasDotChar(const string& str, const int start, const int end) { 131 for (int i = start; i <= end; i++) { 132 //数 133 if (str[i] == dot) { 134 return true;; 135 } 136 } 137 138 return false; 139 } 140 141 //是否是科学计数法数字 142 //规则 143 //1.有且仅有1个e或E 144 //2.e前面有整数或小数 145 //3.e后面有一个整数 146 bool isSciNum(const string& str, const int start, const int end) { 147 if (start > end) { 148 return false; 149 } 150 151 //寻找e 152 int ePos = -1; 153 int eCnt = 0; 154 for (int i = start; i <= end; i++) { 155 if (str[i] == eClass || str[i] == EClass) { 156 ePos = i; 157 eCnt++; 158 } 159 } 160 161 //有且仅有1个e 162 if (ePos < 0 || eCnt > 1) { 163 return false; 164 } 165 166 //前半部分是否合法 167 bool isFrontOk = isFloat(str, start, ePos - 1) || 168 isSignedInteger(str, start, ePos - 1); 169 if (!isFrontOk) { 170 return false; 171 } 172 173 //后半部分是否合法 174 bool isBackOk = isSignedInteger(str, ePos + 1, end); 175 if (!isBackOk) { 176 return false; 177 } 178 179 return true; 180 } 181 182 //是否是小数 183 //规则 184 //1.允许最多用1个正或负号开头 185 //2.dot前后:前面有数字后面没有、前后都有数字、前面没有后面有数字 186 bool isFloat(const string& str, int start, int end) { 187 if (start > end) { 188 return false; 189 } 190 191 //寻找dot 192 int dotPos = -1; 193 int dotCnt = 0; 194 for (int i = start; i <= end; i++) { 195 if (str[i] == dot) { 196 dotPos = i; 197 dotCnt++; 198 } 199 } 200 201 //有且仅有1个dot 202 if (dotPos < 0 || dotCnt > 1) { 203 return false; 204 } 205 bool isFrontOk = false, isBackOk = false; 206 207 //前半部分是否合法 208 if (start == dotPos) { 209 //点前无内容,则必须验证后面是否不带符号且是整数 210 isBackOk = isUnsignedInteger(str, dotPos + 1, end); 211 return isBackOk; 212 } else { 213 //点前有内容,但只有符号位,则必须验证后面是否不带符号且是整数 214 if (start + 1 == dotPos && (str[start] == posFlag || str[start] == negFlag)) { 215 isBackOk = isUnsignedInteger(str, dotPos + 1, end); 216 return isBackOk; 217 } 218 219 //点前有大于1位的内容 220 isFrontOk = isSignedInteger(str, start, dotPos - 1); 221 if (!isFrontOk) { 222 return false; 223 } 224 } 225 226 //后半部分是否合法 227 isBackOk = (dotPos == end) || isUnsignedInteger(str, dotPos + 1, end); 228 if (!isBackOk) { 229 return false; 230 } 231 return true; 232 233 } 234 235 //是否是整数,允许有符号 236 //规则 237 //1.允许最多用1个正或负号开头 238 //2.至少一位数字 239 bool isSignedInteger(const string& str, const int start, const int end) { 240 if (start > end) { 241 return false; 242 } 243 244 //允许首位是符号位 245 if (str[start] == posFlag || str[start] == negFlag) { 246 return isUnsignedInteger(str, start + 1, end); 247 } 248 249 return isUnsignedInteger(str, start, end); 250 } 251 //是否是整数,不允许有符号 252 //规则 253 //1.至少一位数字 254 bool isUnsignedInteger(const string& str, const int start, const int end) { 255 if (start > end) { 256 return false; 257 } 258 259 //查看是否有非数字字符 260 for (int i = start; i <= end; i++) { 261 if (isNumChar(str[i])) { 262 continue; 263 } 264 265 return false; 266 } 267 268 return true; 269 } 270 };