1. 程式人生 > >細數atoi中犯得錯誤(Leetcode第7題)

細數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)
}