【剑指offer】64.表示数值的字符串

总目录:

算法之旅导航目录

 

1.问题描述

请实现一个函数用来判断字符串str是否表示数值(包括科学计数法的数字,小数和整数)。

科学计数法的数字(按顺序)可以分成以下几个部分:
1.若干空格
2.一个整数或者小数
3.(可选)一个 'e' 或 'E' ,后面跟着一个整数(可正可负)
4.若干空格

小数(按顺序)可以分成以下几个部分:
1.若干空格
2.(可选)一个符号字符('+' 或 '-')
3. 可能是以下描述格式之一:
3.1 至少一位数字,后面跟着一个点 '.'
3.2 至少一位数字,后面跟着一个点 '.' ,后面再跟着至少一位数字
3.3 一个点 '.' ,后面跟着至少一位数字
4.若干空格

整数(按顺序)可以分成以下几个部分:
1.若干空格
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 };
View Code

 

posted @ 2022-12-05 17:23  啊原来是这样呀  阅读(31)  评论(0编辑  收藏  举报