String to Integer (atoi) - 複雜的測試

這個題。。是要把字符串轉爲整數。注意是整數,我看到整數的時候鬆了一口氣,沒有小數點的判斷應該更好做。而且基本的轉化函數我想每個程序員都無法忘記:

res=res*10+(str[i]-'0');

其實就是這麼一句話的事情,然而這個題的通過率只有13%,在200多個題目中排名第五。本想不看提示自己寫了一些判斷,然而仍逃不掉wa的結局。

看了下面這堆requirement,還是有很大概率wa。

Requirements for atoi:

The function first discards as many whitespace characters as necessary until the first non-whitespace character is found. Then, starting from this character, takes an optional initial plus or minus sign followed by as many numerical digits as possible, and interprets them as a numerical value.

The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.

If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed.

If no valid conversion could be performed, a zero value is returned. If the correct value is out of the range of representable values, INT_MAX (2147483647) or INT_MIN (-2147483648) is returned.

這個函數在第一個非空白字符出現可以丟棄儘量多的空白字符。然後從這個非空白字符開始,獲取一個初始的加號或者減號,然後之後的數字字符會被轉成一個數。

這個字符串在形成一個數之後可以包含其他字符,函數應該不受他們影響並忽略它們。

如果第一個非空白字符不是一個合法的數字字符,或者這個序列不存在即爲空或者全爲空白字符,不進行任何轉換。

如果沒有進行轉換,函數應該返回0值。如果正確的數值越界了,應該返回2147483647或者-2147483648。

提供一些在dicuss收集的錯誤結果和被wa的樣例:

Input Output Expected
"    b11228552307" 2147483647 0
"+-2" 2 0
"  -0012a42" 0 -12
"   +0 123" 123 0
" 10522545459" 1932610867 2147483647

不得不說測試樣例太兇險。

以下是AC代碼:

 1 class Solution {
 2 public:
 3     int myAtoi(string str) {
 4 
 5         long res=0;
 6         int flag=1;
 7         int i=0;
 8         int count=0;
 9         while(str[i]==' ')
10             i++;
11         if(str[i]=='-')
12         {
13             flag=-1;i++;
14             count++;
15         }
16         else
17             if(str[i]=='+'){
18             flag=1;i++;
19             count++;
20             }
21             else
22             {
23                 if(str[i]>'9'||str[i]<'0')
24                     return 0;
25             }
26         if(count>1)return 0;
27         int numcount=0;
28         for(;i<str.length();i++)
29         {
30             if(str[i]<='9'&&str[i]>='0'){
31                 numcount++;
32                 res=res*10+(str[i]-'0');
33                 if(numcount>11)
34                 {
35                     res=2147483649;
36                     break;
37                 }
38                 continue;
39             }
40             else
41                 break;
42         }
43         if(res>2147483647&&flag==1)return 2147483647;
44         if(res>2147483648&&flag==-1)return -2147483648;
45         int final=res;
46         return final*flag;
47     }
48 };

flag是用來判斷正負的,count是用來判斷正負號數目的,如果讀到非數字字符就結束,numcount是用來判斷越界的。本題我使用了long這個數據類型先進行轉化,這樣在小於11個數的範圍內,long是不會越界的,直接將最後結果賦值給一個int型即可。

在AC之後官方給出瞭解鎖的Solution:

To deal with overflow, inspect the current number before multiplication. If the current number is greater than 214748364, we know it is going to overflow. On the other hand, if the current number is equal to 214748364, we know that it will overflow only when the current digit is greater than or equal to 8.

 Average Rating: 3.7 (305 votes)

大意是在做下一次乘之前判斷下當前數是否是214748364,如果大於這個數繼續乘是一定越界的,如果此時的待加數字是8或者以上也是越界的(正負數還要分7和8討論)。

這個題雖然簡單,但是在寫的時候感覺要考慮的情況還是很多,在判斷越界的方法上有三種:

第一種是這種官方給的做法,推薦使用;

第二種是使用一個更大的數據類型來乘放這個數據,在位數超過10的時候直接break;

第三種是使用字符串匹配,我在Reverse Integer使用的是這個方法。

 

PS:在32位的編譯器上:

unsigned int取值範圍爲:0 - 4294967295;

int的取值範圍是-2147483648 - 2147483647(2的32次方);

 

long 的取值在32位編譯器上和int是相同的,但是在64位的編譯器上是有8個字節的,所以比int表示範圍要大很多。本題中使用long可以通過那個數值溢出的樣例,說明評測機也是64位的。


long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808

__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章