LeetCode65. 有效數字


這題完美的詮釋了什麼叫「面向測試用例編程」。由於要考慮的情況很多,所以基本的思路是先根據給出的測試用例寫出規則判斷無效的情況,然後再根據提交的錯誤對剩下的情況進行特判,如果不滿足所有「無效的情況」,則有效。題目特別提了「我們有意將問題陳述地比較模糊」,這個「有意地陳述地模糊」就很靈性,所以一開始很難考慮到所有情況,WA幾次就知道有哪些測試用例(規則)了。
先從題目給出的測試用例里總結幾點規則:

  1. 給出的字符串可能會包含前綴和後綴的空格,需要先去掉前綴和後綴的空格;
  2. 有可能字符串是一個科學計數法的數字,因此會出現字符’e’或’E’,但’e’(或’E’)只能出現一次,且不能出現在字符串的開頭和結尾位置;
  3. ‘e’(或’E’)的後面可能緊跟一個’+’或’-‘,正負號只能出現在兩個地方,一是字符串開頭,二就是’e'(或’E’)的後面,其他位置如果出現正負號,就可以判定為無效! 另外,’e'(或’E’)後面如果出現了正負號,後面還必須有數字,所以要判斷正負號是不是字符串的結尾,如果是,也可以判定為無效;
  4. 字符串開頭可以是正負號,但如果只有正負號,則無效;
    再從提交的測試用例里總結幾點規則:
  5. 字符串可以由’.’開頭,比如”.1″就表示0.1,這種’.’後面是數字的就是合法的,’.’後面跟着其他字符就是非法的;
  6. ‘.’和’e’只能分別出現一次,多於一次就是無效的
class Solution {
public:
    bool isNumber(string s) {
        int left = 0, right = s.size() - 1;                  //分別從左右過濾掉前綴和後綴的空格
        while(left <= right && s[left] == ' ') {
            ++left;
        }
        while(left <= right && s[right] == ' ') {
            --right;
        }
        if(left > right) {                                    //如果字符串只有空格組成,則無效
            return false;
        }
        s = s.substr(left, right - left + 1);                 //留下刪除掉前綴和後綴的空格之後的字符串
        if(s[0] == '+' || s[0] == '-') {                      //如果字符串由正負號開頭,則刪掉開頭的字符串再作判斷
            s = s.substr(1);                                  //substr只傳入一個參數1,表示留下從第一個位置到末尾的子串(即刪除第0個位置的正負號)
        }
        if(s.empty()) {                                       //如果刪掉正負號之後字符串為空,則無效
            return false;
        }
        if(s[0] == '.' && (s.size() == 1 || s[1] == 'e' || s[1] == 'E')) {    //如果字符串有'.'開頭,則有三種情況是無效的:(1)字符串只有一個字符'.'; (2)下一個字符是'e'; (3)下一個字符是'E'。 實際上,只要'.'後面的字符不是數字就都是無效的,只不過其他情況在別處判斷了。
            return false;
        }
        int dotNum = 0, eNum = 0;                  //記錄'.'和'e'(或'E')的數量
        for(int i = 0; i < s.size(); ++i) {
            if(s[i] == '.') {                      
                if(dotNum > 0 || eNum > 0) {       //如果'.'出現次數大於1或者'.'在'e'(或'E')之後出現,則無效
                    return false;
                } else {
                    ++dotNum;
                }
            } else if(s[i] == 'e' || s[i] == 'E') {            
                if(i == 0 || i == s.size() - 1 || eNum > 0) {      //如果'e'(或'E')出現在開頭或者結尾位置,或者出現次數大於1,則無效
                    return false;
                } else if(s[i + 1] == '+' || s[i + 1] == '-') {     //如果'e'(或'E')後面的字符是正負號,需要特判
                    if(i + 1 == s.size() - 1) {                     //正負號後面需要有數字,如果正負號已經是最後一個字符了(後面啥都沒),則無效
                        return false;
                    } else {
                        ++i;                                        //如果正負號後面還有東西,我們就跳過正負號,繼續判斷後面的
                    }
                }
                ++eNum;
            } else if(!(s[i] >= '0' && s[i] <= '9')) {              //其他情況的字符只能是數字,其他都是無效的
                return false;
            }
        }
        return true;                                                //如果不滿足上述任何情況,我們就認為字符串可以表示為一個有效的數字!
    }
};

複雜度分析:由於只遍歷一遍字符串,時間複雜度是O(n);只開了常數個變量,空間複雜度是O(1)。

Tags: