本文共 2808 字,大约阅读时间需要 9 分钟。
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−231, 231 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
题目要求返回值为int32
,而题目给的函数返回值是int
,因此不能直接把转换成int32
的值返回,取巧的方式就是判断一下返回值是否在int32
范围里,不在则返回0
。
方法一:
执行用时 :0 ms/4 ms, 击败了100.00%/45.50% 的用户 内存消耗 :2.3 MB, 击败了5.56%的用户本方法先将整数转换为字符串,获得正负符号后开始循环转换位置(和之前字符串转换的题目一样)。转换完成后合并,再变成整数返回。
func reverse2(x int) int { y := strings.Split(strconv.Itoa(x), "") i := 0 l := len(y) if y[0] == "-" { i = 1 l = l + 1 } j := l / 2 for ; i < j; i++ { y[i], y[l-1-i] = y[l-1-i], y[i] } z := "" for _, v := range y { z += v } x, _ = strconv.Atoi(z) // if判断语句仅针对本题中要求的返回值为32位,不要求的话本if语句可以删除 if x > 2147483647 || x < -2147483648 { return 0 } return x}
方法二:
执行用时 :0 ms/4 ms, 击败了100.00%/45.5% 的用户 内存消耗 :2.2 MB, 击败了74.60%/30.95%的用户本方法利用了数学的方法,嗯嗯,挺有意思,后面详解,还涉及到一个最大最小值衍生出的知识点。
func reverse3(x int) int { var y int = 0 for x != 0 { y = y*10 + x%10 x = x / 10 } // if判断语句仅针对本题中要求的返回值为32位,不要求的话本if语句可以删除 MAX_INT32 := int(^uint32(0) >> 1) MIN_INT32 := ^MAX_INT32 //if y > 2147483647 || y < -2147483648 { if y > MAX_INT32 || y < MIN_INT32 { return 0 } return y}
只解析方法二中的三个知识点:
按照字符串的理解方法,很简单,前后交换即可。
但方法二中使用了数学方法(原数x
,新数y
): for x != 0 { y = y*10 + x%10 x = x / 10}
怎么理解这一段呢?我们利用数字123
来进行分析:
// 第一次循环y=0*10+123%10=0+3=3x=123/10=12// 第二次循环y=3*10+12%10=30+2=32x=12/10=1// 第三次循环y=32*10+1%10=320+1=321x=1/10=0
每一次循环需要实现:
两种理解:
- 旧值
x
不断割下末尾数字,并将该数字不断补充到新值y
右侧(即y
向左移动一位+x
末尾数字)- 公式一中得到
x
末尾数字用来生成新值y
,公式二中砍掉已经在公式一中使用的末尾数字,生成新的x
,在下次循环中给公式一使用。
公式一:
y = y*10 + x%10
每次循环时将y值10(提升一位)再加上当前x的末尾值。* y*10
的值,意味着将现在的y值提升一位;x%10
的值,余数就是x个位数的值。公式二:
x = x / 10
每次循环时x
都将砍掉末尾的数字,这样才能让下次循环时公式一中的x
正常使用 x / 10
得到的整数商(不含余数)即意味着x
被砍了最后一位~~x
只剩一位数时,计算所得整数商为0
,此时停止循环。在未来的计算中,可能会经常用到公式一第2条和公式二第1条的思路。
题目要求不能超出int32的范围,那么最简单做法就是直接判断int32的上下限,即
if y > 2147483647 || y < -2147483648 { ...}
我们这里扩展一下知识点:
一、获得int32的最大和最小值
举例uint
和int
,参考链接: 1. 无符号整型uint,其最小值是0,其二进制表示的所有位都为0,
const UINT_MIN uint = 0
其最大值的二进制表示的所有位都为1,那么,
const UINT_MAX = ^uint(0)
2. 有符号整型int,根据补码,其最大值二进制表示,首位0,其余1,那么,
const INT_MAX = int(^uint(0) >> 1)
根据补码,其最小值二进制表示,首位1,其余0,那么,
const INT_MIN = ^INT_MAX
3. 本例中的语句针对int32,那么:
MAX_INT32 := int(^uint32(0) >> 1)MIN_INT32 := ^MAX_INT32if y > MAX_INT32 || y < MIN_INT32 { return 0}
二、为什么不用min和max直接判断范围
go目前没有给出int
的最大最小值,只在math
库中提供了float
的最大最小值(math.Min(float64, float64) float64
和math.Max(float64, float64) float64
),可能是go觉得int
的范围判断太简单了,自己写一个函数即可。 func Min(x, y int64) int64 { if x < y { return x } return y}
详细内容参考链接:
公式二第1条,为什么整数相除得到的商即是我们需要的?
因为在go中,整数相除的商为整数,且商不进行四舍五入,直接去掉小数点后面的数字。 比如:fmt.Println(125 / 3)fmt.Println(125 / 3.0)// 输出:// 41// 41.666666666666664
由此可知,如果要让两个整数相除的商得到浮点,则只需要除数或被除数是浮点数即可。具体使用方法参考:
转载地址:http://dtkpi.baihongyu.com/