細數atoi中犯得錯誤(Leetcode第7題)
題目原文
實現 atoi,將字串轉為整數。
該函式首先根據需要丟棄任意多的空格字元,直到找到第一個非空格字元為止。如果第一個非空字元是正號或負號,選取該符號,並將其與後面儘可能多的連續的數字組合起來,這部分字元即為整數的值。如果第一個非空字元是數字,則直接將其與之後連續的數字字元組合起來,形成整數。
字串可以在形成整數的字元後面包括多餘的字元,這些字元可以被忽略,它們對於函式沒有影響。
當字串中的第一個非空字元序列不是個有效的整數;或字串為空;或字串僅包含空白字元時,則不進行轉換。
若函式不能執行有效的轉換,返回 0。
說明:
假設我們的環境只能儲存 32 位有符號整數,其數值範圍是 [−231, 231 − 1]。如果數值超過可表示的範圍,則返回 INT_MAX (231 − 1) 或 INT_MIN (−231) 。
示例 1:
輸入: “42”
輸出: 42
示例 2:
輸入: " -42"
輸出: -42
解釋: 第一個非空白字元為 ‘-’, 它是一個負號。
我們儘可能將負號與後面所有連續出現的數字組合起來,最後得到 -42 。
示例 3:
輸入: “4193 with words”
輸出: 4193
解釋: 轉換截止於數字 ‘3’ ,因為它的下一個字元不為數字。
示例 4:
輸入: “words and 987”
輸出: 0
解釋: 第一個非空字元是 ‘w’, 但它不是數字或正、負號。
因此無法執行有效的轉換。
示例 5:
輸入: “-91283472332”
輸出: -2147483648
解釋: 數字 “-91283472332” 超過 32 位有符號整數範圍。
因此返回 INT_MIN (−231) 。
思路分析
這並不是一道難題,只是比較繁瑣,考慮的情況多,用來訓練用例設計能力是一個不錯的選擇.
func getEndIndex(str string) int {
for i,v := range str{
if v > '9' || v < '0' {
return i
}
}
return len(str)
}
func myAtoi(str string) int {
new_str := strings.TrimSpace(str)
start := 0;
end := 0;
flag := 0 ;
if len(new_str) ==0 {
return 0
}
switch {
case new_str[0] == '-' : {
flag = 0
start =1
end =getEndIndex(new_str[1:])+1
}
case new_str[0] =='+':
flag = 1
start =1
end =getEndIndex(new_str[1:])+1
case new_str[0] <= '9' && '0' <= new_str[0]: {
flag =1
start =0
end =getEndIndex(new_str)
}
default :{
return 0
}
}
if end -start > 10{
if flag ==0{
return -2147483648
}else{
return 2147483647
}
}
fmt.Println(new_str,start,end,new_str[start:end])
number, _ := strconv.ParseInt(new_str[start:end], 10, 64)
if flag == 0 {
if -number < -2147483648{
return -2147483648
}else{
return int(-number)
}
}else{
if number > 2147483647{
return 2147483647
}else{
return int(number)
}
}
return int(number)
}
這是我提交的第一個版本,首先反省一下,一個函式太長了,邏輯複雜就容易出問題.
總體思路是:
先排除不滿足數字條件的情況,取出數字部分,
因為要求的32位的轉換,超過32位,就返回32位的最大值,所以可以使用找出32位數字的最大長度
如果字串的長度超過了32位的最大數字長度,就直接返回32位最大正數或者32位的最大負數
否則,可以使用64位的字元轉數字,然後再和32位的最大數字比較
本次提交的的問題
1.沒有考慮 首位為0的情況。
2. myAtoi 函式寫的太長了需要精簡。
所以有了第二次提交
func getEndIndex(str string) int {
for i, v := range str {
if v > '9' || v < '0' {
return i
}
}
return len(str)
}
func trimSign(new_str string) (fg bool, out_str string) {
var flag bool = true
str := "";
// 符號位
if new_str[0] == '-' {
flag = false
str = strings.Replace(new_str,"-","",1)
} else {
if new_str[0] == '+' {
str = strings.Replace(new_str,"+","",1)
}else{
str=new_str;
}
}
return flag, str
}
func trimPreZero(new_str string)(out string){
for i, v := range new_str {
if v != '0' {
return strings.Replace(new_str,"0","",i)
}
}
return new_str
}
// 缺乏對 首位不是符號位,但是首位為0的處理.
func myAtoi(str string) int {
new_str := strings.TrimSpace(str)
end := 0
flag, new_str := trimSign(new_str)
new_str = trimPreZero(new_str)
if len(new_str) == 0 {
return 0
}
if new_str[0] <= '9' && '0' < new_str[0] {
end = getEndIndex(new_str)
} else {
return 0
}
if end > 10 {
if flag == false {
return -2147483648
} else {
return 2147483647
}
}
fmt.Println(new_str, end, new_str[:end])
number, _ := strconv.ParseInt(new_str[:end], 10, 64)
if flag == false {
if -number < -2147483648 {
return -2147483648
} else {
return int(-number)
}
} else {
if number > 2147483647 {
return 2147483647
} else {
return int(number)
}
}
return int(number)
}
第二次提交執行錯誤,
原因是對輸入空字串的校驗,放在使用(trimSign,trimPreZero)後面,
空字串的校驗,我在第一次提交的時候是測試過的,修改後,之前的用例沒有覆蓋。
正確的提交
func getEndIndex(str string) int {
for i, v := range str {
if v > '9' || v < '0' {
return i
}
}
return len(str)
}
func trimSign(new_str string) (fg bool, out_str string) {
var flag bool = true
str := "";
// 符號位
if new_str[0] == '-' {
flag = false
str = strings.Replace(new_str,"-","",1)
} else {
if new_str[0] == '+' {
str = strings.Replace(new_str,"+","",1)
}else{
str=new_str;
}
}
return flag, str
}
func trimPreZero(new_str string)(out string){
for i, v := range new_str {
if v != '0' {
return strings.Replace(new_str,"0","",i)
}
}
return new_str
}
// 缺乏對 首位不是符號位,但是首位為0的處理.
func myAtoi(str string) int {
new_str := strings.TrimSpace(str)
end := 0
if len(new_str) == 0 {
return 0
}
flag, new_str := trimSign(new_str)
new_str = trimPreZero(new_str)
if len(new_str) == 0 {
return 0
}
//fmt.Println(new_str, end, new_str[:end])
if new_str[0] <= '9' && '0' < new_str[0] {
end = getEndIndex(new_str)
} else {
return 0
}
if end > 10 {
if flag == false {
return -2147483648
} else {
return 2147483647
}
}
//fmt.Println(new_str, end, new_str[:end])
number, _ := strconv.ParseInt(new_str[:end], 10, 64)
if flag == false {
if -number < -2147483648 {
return -2147483648
} else {
return int(-number)
}
} else {
if number > 2147483647 {
return 2147483647
} else {
return int(number)
}
}
return int(number)
}