本文參考自《劍指offer》一書,代碼采用Java語言。
題目
請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串“+100”、“5e2”、“-123”、“3.1416”及“-1E-16”都表示數值,但“12e”、“1a3.14”、“1.2.3”、“+-5”及“12e+5.4”都不是。
思路
剛開始的思路是從頭到尾遍歷,對遇到的不同情況進行分析,但很容易出錯。因此采用《劍指OFFER》一書的方法:將數字的形式總結為:(A.B E/e A) ,按順序進行判斷(A代表帶符號整數,B代表不帶符號整數)。
另一種思路:借助幾個flag從頭到尾遍歷,具體代碼見:【LeetCode】65. Valid Number
測試算例
1.功能測試(正負數;含整數與不含整數部分;含與不含小數部分;含與不含指數部分;不匹配情況)
2.特殊測試(null,空字符串)
完整Java代碼
(含測試代碼)
/**
*
* @Description 面試題20:表示數值的字符串
*
* @author yongh
* @date 2018年9月22日 上午11:15:13
*/
// 題目:請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,
// 字符串“+100”、“5e2”、“-123”、“3.1416”及“-1E-16”都表示數值,但“12e”、
// “1a3.14”、“1.2.3”、“+-5”及“12e+5.4”都不是
public class NumericStrings {
/*
* 數字的基本格式為:(A.B E/e A) ,按順序進行判斷
* //A代表帶符號整數,B代表不帶符號整數
* 小心:時刻要注意數組越界問題!
*/
public boolean isNumeric(char[] str) {
if (str == null || str.length == 0)
return false;
int[] index = new int[1];
index[0] = 0; // 用於記錄當前字符位置
// 先判斷A
boolean isNumeric; //用於記錄是否滿足條件
isNumeric = isInteger(str, index);
// 判斷B
if (index[0] < str.length && (str[index[0]] == '.')) {
index[0]++;
isNumeric = isUnsignedInteger(str, index) || isNumeric; // .B和A.和A.B形式均可以
}
// 判斷e后面的A
if (index[0] < str.length && (str[index[0]] == 'e' || str[index[0]] == 'E')) {
index[0]++;
isNumeric = isInteger(str, index) && isNumeric;
}
if (isNumeric && index[0] == str.length)
return true;
else
return false;
}
private boolean isInteger(char[] str, int[] index) { // 用int[]才能傳值,int的話需要定義index為全局變量
if (index[0] < str.length && (str[index[0]] == '+' || str[index[0]] == '-'))
index[0]++;
return isUnsignedInteger(str, index);
}
private boolean isUnsignedInteger(char[] str, int[] index) {
int start = index[0];
while (index[0] < str.length && (str[index[0]] - '0' <= 9 && str[index[0]] - '0' >= 0))
index[0]++;
if (index[0] > start)
return true;
else
return false;
}
// =======測試代碼=========
void test(String testName, char[] str, boolean expected) {
System.out.print(testName + ":");
if (isNumeric(str) == expected)
System.out.println(" passed!");
else
System.out.println(" failed!");
}
void test1() {
char[] str = null;
test("test1", str, false);
}
void test2() {
char[] str = {};
test("test2", str, false);
}
void test3() {
String string ="e3";
char[] str=string.toCharArray();
test("test3", str, false);
}
void test4() {
String string ="3e1.2";
char[] str=string.toCharArray();
test("test4", str, false);
}
void test5() {
String string ="e3";
char[] str=string.toCharArray();
test("test5", str, false);
}
void test6() {
String string ="1.2e3";
char[] str=string.toCharArray();
test("test6", str, true);
}
void test7() {
String string ="-.2e3";
char[] str=string.toCharArray();
test("test7", str, true);
}
void test8() {
String string ="-.2e-3";
char[] str=string.toCharArray();
test("test8", str, true);
}
void test9() {
String string ="1.e-3";
char[] str=string.toCharArray();
test("test9", str, true);
}
void test10() {
String string ="1.";
char[] str=string.toCharArray();
test("test10", str, true);
}
void test11() {
String string =".2";
char[] str=string.toCharArray();
test("test11", str, true);
}
void test12() {
String string ="12e3";
char[] str=string.toCharArray();
test("test12", str, true);
}
public static void main(String[] args) {
NumericStrings demo = new NumericStrings();
demo.test1();
demo.test2();
demo.test3();
demo.test4();
demo.test5();
demo.test6();
demo.test7();
demo.test8();
demo.test9();
demo.test10();
demo.test11();
demo.test12();
}
}
test1: passed! test2: passed! test3: passed! test4: passed! test5: passed! test6: passed! test7: passed! test8: passed! test9: passed! test10: passed! test11: passed! test12: passed!
收獲
對字符串進行依次判斷時,定義一個Boolean變量,每判斷一部分進行更新,最終該變量即為判斷結果,不需要進行循環判斷。(即本例中的isNumeric變量)
代碼38行,別忘記了最后對index是否到達結尾進行判斷。
注意:第31行isNumeric = isUnsignedInteger(str, index) || isNumeric; 的順序不能反了,不能寫成isNumeric = isNumeric || isUnsignedInteger(str, index) ; 否則當isNumeric為True時,不會判斷后半部分,index就不會走向'e',從而導致錯誤。
