題目String to Integer (atoi)(難度Medium)
git
大意是找出給定字串開頭部分的整型數值,忽略開頭的空格,注意符號,對超出Integer的數作取邊界值處理。算法
方案1測試
1 class Solution { 2 fun myAtoi(str: String): Int { 3 val maxInt = "2147483647" 4 val maxIntS = "+2147483647" 5 val minIntS = "-2147483648" 6 val lengthMI = maxInt.length 7 val lengthMIS = maxIntS.length 8 var result = "" 9 var strR = str.trim() 10 11 //strR爲空 12 if (strR.isEmpty()) { 13 return 0 14 } 15 16 //strR不爲空,且不以+/-開頭 17 if ('+' != strR[0] && '-' != strR[0]) { 18 //不以數字開頭 19 if (!strR[0].isDigit()) { 20 return 0 21 } 22 23 //以數字開頭 24 for (c in strR) { 25 if (c.isDigit()) { 26 result += c 27 } else { 28 break 29 } 30 } 31 if (result.length > lengthMI || 32 (result.length == lengthMI && result > maxInt)) { 33 result = maxInt 34 } 35 return result.toInt() 36 } 37 38 //strR以+/-開頭 39 //後不是跟數字 40 if (strR.length == 1 || (strR.length > 1 && !strR[1].isDigit())) { 41 return 0 42 } 43 44 //後跟數字 45 result += strR[0] 46 for (c in strR.subSequence(1, strR.length)) { 47 if (c.isDigit()) { 48 result += c 49 } else { 50 break 51 } 52 } 53 if (result[0] == '+' && (result.length > lengthMIS || 54 (result.length == lengthMIS && result > maxIntS))) { 55 result = maxIntS 56 } else if (result[0] == '-' && (result.length > lengthMIS || 57 (result.length == lengthMIS && result > minIntS))) { 58 result = minIntS 59 } 60 return result.toInt() 61 } 62 }
將數字及其長度這種常量抽象出來,不至於代碼中充斥着一丟重複的數字和長度計算,爭取在平時的編碼過程當中養成好習慣。編碼
說到習慣,代碼中還有一點提一下,在對字串進行符號存在性、符號後字符等多種狀況的判斷時並無使用一長串的if..else..,而是每一個小分支直接用return終止。這樣的好處是代碼可讀性與可維護性強,編碼過程當中不會因分支過多而可能搞混或出現漏處理的狀況。spa
代碼先用trim()將字串開頭的空字符去除(若是存在的話),而後對有/無符號、是否緊跟數字等多種狀況作了清晰的判斷和相應的處理。code
LeetCode提交詳情blog
從上圖看,總共測試了1047個數據,耗時582ms。ip
測試代碼:leetcode
1 fun main(args: Array<String>) { 2 val start = System.currentTimeMillis() 3 println(Solution().myAtoi("-0000000000000000006666666bb6aa")) 4 val end = System.currentTimeMillis() 5 println(end - start) 6 }
測試數據rem
這篇文章先不看算法的耗時,重點關注用於測試的數據。
根據題目的描述,給定字串中應該是能夠包含任意字符的,須要咱們用代碼進行處理,輸出要求的結果。
那麼,來看幾組測試字串及其輸出結果:
" +0aa",0,返回正確的數值0
" +066bb6aa",66
" -06 6bb6aa",-6
" -06666666666666666666bb6aa",-2147483648,數值向下越界
"06666666666666666666bb6aa",2147483647,數值向上越界
"0000000000000000006666666bb6aa",2147483647,???錯誤的結果,應該是6666666
"a0000000066bb6aa",0,不以符號或數字開頭,直接返回0
"- 0000000066bb6aa",0,符號後跟的不是數字,直接返回0
結果分析
能夠看到,除了打問號的那一組測試案例,其餘均獲得了符號要求的結果。即對於不知足要求的字串直接返回0,字串開頭的空字符不該影響結果,獲取數據過程當中遇到非數字立馬終止等。
因爲題目的描述中並無具體指明測試字串會是什麼樣,也沒有針對開頭不少0的狀況進行說明,雖然提交後是accepted狀態,但爲了算法的嚴謹性,仍是須要對上面出錯的狀況作進一步的處理。
方案2
1 class Solution { 2 fun myAtoi(str: String): Int { 3 val maxInt = "2147483647" 4 val maxIntS = "+2147483647" 5 val minIntS = "-2147483648" 6 val lengthMI = maxInt.length 7 val lengthMIS = maxIntS.length 8 var result = "" 9 var strR = str.trim() 10 11 //strR爲空 12 if (strR.isEmpty()) { 13 return 0 14 } 15 16 //strR不爲空,且不以+/-開頭 17 if ('+' != strR[0] && '-' != strR[0]) { 18 //不以數字開頭 19 if (!strR[0].isDigit()) { 20 return 0 21 } 22 23 //以數字開頭 24 for (c in strR) { 25 if (c.isDigit()) { 26 result += c 27 } else { 28 break 29 } 30 } 31 while (result.length > 1 && result[0] == '0') { 32 result = result.removeRange(0, 1) 33 } 34 if (result.length > lengthMI || 35 (result.length == lengthMI && result > maxInt)) { 36 result = maxInt 37 } 38 return result.toInt() 39 } 40 41 //strR以+/-開頭 42 //後不是跟數字 43 if (strR.length == 1 || (strR.length > 1 && !strR[1].isDigit())) { 44 return 0 45 } 46 47 //後跟數字 48 result += strR[0] 49 for (c in strR.subSequence(1, strR.length)) { 50 if (c.isDigit()) { 51 result += c 52 } else { 53 break 54 } 55 } 56 while (result.length > 2 && result[1] == '0') { 57 result = result.removeRange(1, 2) 58 } 59 if (result[0] == '+' && (result.length > lengthMIS || 60 (result.length == lengthMIS && result > maxIntS))) { 61 result = maxIntS 62 } else if (result[0] == '-' && (result.length > lengthMIS || 63 (result.length == lengthMIS && result > minIntS))) { 64 result = minIntS 65 } 66 return result.toInt() 67 } 68 }
代碼第31-33及56-58行,其實就是針對數據開頭的0進行了移除(固然數據只有一個數字且爲0是要保留的),由於開頭0的存在不會影響數據的大小,反而會干擾字串的長度計算。測試結果:
"-0000000000000000006666666bb6aa",-6666666