Golang面试考题记录 ━━ 整数反转 解答及扩展的三个知识点

===问:

给出一个 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=3
x=123/10=12

// 第二次循环
y=3*10+12%10=30+2=32
x=12/10=1

// 第三次循环
y=32*10+1%10=320+1=321
x=1/10=0

每一次循环需要实现:

两种理解:

  1. 旧值x不断割下末尾数字,并将该数字不断补充到新值y右侧(即y向左移动一位+x末尾数字)
  2. 公式一中得到x末尾数字用来生成新值y,公式二中砍掉已经在公式一中使用的末尾数字,生成新的x,在下次循环中给公式一使用。

公式一:
y = y*10 + x%10
每次循环时将y值10(提升一位)再加上当前x的末尾值。*

  1. y*10的值,意味着将现在的y值提升一位;
  2. x%10的值,余数就是x个位数的值。
  3. 两个值相加实现目标

公式二:
x = x / 10
每次循环时x都将砍掉末尾的数字,这样才能让下次循环时公式一中的x正常使用

  1. x / 10得到的整数商(不含余数)即意味着x被砍了最后一位~~
  2. x只剩一位数时,计算所得整数商为0,此时停止循环。

在未来的计算中,可能会经常用到公式一第2条和公式二第1条的思路。

二、int32最大最小值的判断

题目要求不能超出int32的范围,那么最简单做法就是直接判断int32的上下限,即

if y > 2147483647 || y < -2147483648 {
	...
}

我们这里扩展一下知识点:

一、获得int32的最大和最小值
举例uintint,参考链接:《golang 整数常量INT_MAX INT_MIN最大值最小值》

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_INT32
if y > MAX_INT32 || y < MIN_INT32 {
	return 0
}

二、为什么不用min和max直接判断范围
go目前没有给出int的最大最小值,只在math库中提供了float的最大最小值(math.Min(float64, float64) float64math.Max(float64, float64) float64),可能是go觉得int的范围判断太简单了,自己写一个函数即可。

func Min(x, y int64) int64 {
    if x < y {
        return x
    }
    return y
}

详细内容参考链接:《go语言为什么没有min/max(int, int)函数 》

三、整数相除的结果

公式二第1条,为什么整数相除得到的商即是我们需要的?
因为在go中,整数相除的商为整数,且商不进行四舍五入,直接去掉小数点后面的数字。
比如:

fmt.Println(125 / 3)
fmt.Println(125 / 3.0)

// 输出:
// 41
// 41.666666666666664

由此可知,如果要让两个整数相除的商得到浮点,则只需要除数或被除数是浮点数即可。具体使用方法参考:《golang整数与小数间的加减乘除》

发布了44 篇原创文章 · 获赞 1 · 访问量 3595

猜你喜欢

转载自blog.csdn.net/snans/article/details/105372323