题目String to Integer (atoi)(难度Medium)
大意是找出给定字串开头部分的整型数值,忽略开头的空格,注意符号,对超出Integer的数做取边界值处理。
方案1
class Solution { fun myAtoi(str: String): Int { val maxInt = " val maxIntS = "+2147483647" val minIntS = "-2147483648" val lengthMI = maxInt.length val lengthMIS = maxIntS.length var result = "" var strR = str.trim() //strR为空 if (strR.isEmpty()) { } //strR不为空,且不以+/-开头 ] && ]) { //不以数字开头 ].isDigit()) { } //以数字开头 for (c in strR) { if (c.isDigit()) { result += c } else { break } } if (result.length > lengthMI || (result.length == lengthMI && result > maxInt)) { result = maxInt } return result.toInt() } //strR以+/-开头 //后不是跟数字 || (strR.length > && !strR[].isDigit())) { } //后跟数字 result += strR[] , strR.length)) { if (c.isDigit()) { result += c } else { break } } ] == '+' && (result.length > lengthMIS || (result.length == lengthMIS && result > maxIntS))) { result = maxIntS } ] == '-' && (result.length > lengthMIS || (result.length == lengthMIS && result > minIntS))) { result = minIntS } return result.toInt() } }
将数字及其长度这种常量抽象出来,不至于代码中充斥着一丢重复的数字和长度计算,争取在平时的编码过程中养成好习惯。
说到习惯,代码中还有一点提一下,在对字串进行符号存在性、符号后字符等多种情况的判断时并没有使用一长串的if..else..,而是每个小分支直接用return终止。这样的好处是代码可读性与可维护性强,编码过程中不会因分支过多而可能搞混或出现漏处理的情况。
代码先用trim()将字串开头的空字符去除(如果存在的话),然后对有/无符号、是否紧跟数字等多种情况做了清晰的判断和相应的处理。
LeetCode提交详情
从上图看,总共测试了1047个数据,耗时582ms。
测试代码:
fun main(args: Array<String>) { val start = System.currentTimeMillis() println(Solution().myAtoi("-0000000000000000006666666bb6aa")) val end = System.currentTimeMillis() println(end - start) }
测试数据
这篇文章先不看算法的耗时,重点关注用于测试的数据。
根据题目的描述,给定字串中应该是可以包含任意字符的,需要我们用代码进行处理,输出要求的结果。
那么,来看几组测试字串及其输出结果:
" +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
class Solution { fun myAtoi(str: String): Int { val maxInt = " val maxIntS = "+2147483647" val minIntS = "-2147483648" val lengthMI = maxInt.length val lengthMIS = maxIntS.length var result = "" var strR = str.trim() //strR为空 if (strR.isEmpty()) { } //strR不为空,且不以+/-开头 ] && ]) { //不以数字开头 ].isDigit()) { } //以数字开头 for (c in strR) { if (c.isDigit()) { result += c } else { break } } && result[] == ') { result = result.removeRange(, ) } if (result.length > lengthMI || (result.length == lengthMI && result > maxInt)) { result = maxInt } return result.toInt() } //strR以+/-开头 //后不是跟数字 || (strR.length > && !strR[].isDigit())) { } //后跟数字 result += strR[] , strR.length)) { if (c.isDigit()) { result += c } else { break } } && result[] == ') { result = result.removeRange(, ) } ] == '+' && (result.length > lengthMIS || (result.length == lengthMIS && result > maxIntS))) { result = maxIntS } ] == '-' && (result.length > lengthMIS || (result.length == lengthMIS && result > minIntS))) { result = minIntS } return result.toInt() } }
代码第31-33及56-58行,其实就是针对数据开头的0进行了移除(当然数据只有一个数字且为0是要保留的),因为开头0的存在不会影响数据的大小,反而会干扰字串的长度计算。测试结果:
"-0000000000000000006666666bb6aa",-6666666