我在上次面试中遇到的一个问题是:
设计函数f,使得:f(f(n))==-n其中n是32位有符号整数;你不能用复数算术。如果你不能为整个数字范围设计这样的函数,那么就尽可能为最大范围设计它。
有什么想法吗?
我在上次面试中遇到的一个问题是:
设计函数f,使得:f(f(n))==-n其中n是32位有符号整数;你不能用复数算术。如果你不能为整个数字范围设计这样的函数,那么就尽可能为最大范围设计它。
有什么想法吗?
当前回答
怎么样
int f(int n)
{
return -abs(n);
}
其他回答
在awk中,由于几乎没有任何信息被传递,因此必须求助于允许将状态信息作为函数返回的一部分传递的方法,而不会危及传递内容的可用性:
jot - -5 5 | mawk 'function _(__,___) {
return (__~(___=" ")) \
\
? substr("",sub("^[ ]?[+- ]*",\
substr(" -",__~__,index("_"___,___)-\
(__~"[-]")),__))\
(__~"[-]"?"":___)__\
: (+__<-__?___:(___)___)__
} BEGIN { CONVFMT=OFMT="%.17g"
} {
print "orig", +(__=$(__<__))<-__?__:" "__,
"f(n)....", _(__),_(_(__)),_(_(_(__))),
_(_(_(_(__)))), _(_(_(_(_(__)))))
}' |gcat -n | lgp3 5
1 orig -5 f(n).... -5 5 -5 5 -5
2 orig -4 f(n).... -4 4 -4 4 -4
3 orig -3 f(n).... -3 3 -3 3 -3
4 orig -2 f(n).... -2 2 -2 2 -2
5 orig -1 f(n).... -1 1 -1 1 -1
6 orig 0 f(n).... 0 -0 0 -0 0
7 orig 1 f(n).... 1 -1 1 -1 1
8 orig 2 f(n).... 2 -2 2 -2 2
9 orig 3 f(n).... 3 -3 3 -3 3
10 orig 4 f(n).... 4 -4 4 -4 4
11 orig 5 f(n).... 5 -5 5 -5 5
因此,这样做的限制是,只有整数或浮点值已经是字符串格式,可以在没有风险的情况下使用,因为额外的ASCII空间\040作为状态信息
这种方法的优点是
它愿意为您提供“负零”,对于绝对值小于2^53的整数,简单地添加加号,即+f(f(_))函数调用本身将具有隐式代表您完成类型铸造,结果值将再次为数字对于大整数,只需减去()任何前导空格轻松处理大整数,而不会丢失精度从类型转换为双精度浮点
`
1 orig -99999999999999999999999999999999
f(n)....
-99999999999999999999999999999999
99999999999999999999999999999999
-99999999999999999999999999999999
99999999999999999999999999999999
-99999999999999999999999999999999
2 orig -1239999999999999999999999999999
f(n).... -1239999999999999999999999999999
1239999999999999999999999999999
-1239999999999999999999999999999
1239999999999999999999999999999
-1239999999999999999999999999999`
int f( int n ){
return n==0?0:(n&1?n:-n)+(n<0?-1:1);
}
事实上,这些问题更多的是关于面试官与规范、设计、错误处理、边界案例以及为解决方案选择合适的环境等进行斗争,而不是关于实际解决方案。然而::)
这里的函数是围绕封闭的4循环思想编写的。如果函数f只允许落在有符号的32位整数上,那么上面的各种解决方案都将起作用,除了其他人指出的三个输入范围数。minint永远不会满足函数方程,因此如果这是一个输入,我们将引发一个异常。
在这里,我允许Python函数操作并返回元组或整数。任务规范承认这一点,它只指定函数的两个应用程序应该返回一个与原始对象相等的对象,如果它是int32。(我会询问有关规范的更多细节)
这使得我的轨道可以很好且对称,并且可以覆盖所有输入整数(minint除外)。我最初设想的循环是访问半整数值,但我不想陷入舍入错误。因此是元组表示。这是一种将复杂旋转作为元组隐藏的方式,而不使用复杂的算术机制。
注意,在调用之间不需要保留任何状态,但调用者确实需要允许返回值为元组或int。
def f(x) :
if isinstance(x, tuple) :
# return a number.
if x[0] != 0 :
raise ValueError # make sure the tuple is well formed.
else :
return ( -x[1] )
elif isinstance(x, int ) :
if x == int(-2**31 ):
# This value won't satisfy the functional relation in
# signed 2s complement 32 bit integers.
raise ValueError
else :
# send this integer to a tuple (representing ix)
return( (0,x) )
else :
# not an int or a tuple
raise TypeError
因此,将f应用于37两次得到-37,反之亦然:
>>> x = 37
>>> x = f(x)
>>> x
(0, 37)
>>> x = f(x)
>>> x
-37
>>> x = f(x)
>>> x
(0, -37)
>>> x = f(x)
>>> x
37
将f两次应用于零得到零:
>>> x=0
>>> x = f(x)
>>> x
(0, 0)
>>> x = f(x)
>>> x
0
我们处理一个问题没有解决方案的情况(在int32中):
>>> x = int( -2**31 )
>>> x = f(x)
Traceback (most recent call last):
File "<pyshell#110>", line 1, in <module>
x = f(x)
File "<pyshell#33>", line 13, in f
raise ValueError
ValueError
如果你认为函数通过模拟乘以i的90度旋转打破了“无复杂算术”规则,我们可以通过扭曲旋转来改变这一点。这里元组表示半整数,而不是复数。如果你在数字线上追踪轨道,你会得到满足给定函数关系的非相交循环。
f2: n -> (2 abs(n) +1, 2 sign( n) ) if n is int32, and not minint.
f2: (x, y) -> sign(y) * (x-1) /2 (provided y is \pm 2 and x is not more than 2maxint+1
练习:通过修改f来实现这个f2。还有其他解决方案,例如,中间着落点是有理数而不是半整数。有一个分数模块可能很有用。你需要一个符号函数。
这个练习让我真正体会到了动态类型语言的乐趣。我在C中看不到这样的解决方案。
这将在非常广泛的数字范围内发挥作用:
static int f(int n)
{
int lastBit = int.MaxValue;
lastBit++;
int secondLastBit = lastBit >> 1;
int tuple = lastBit | secondLastBit;
if ((n & tuple) == tuple)
return n + lastBit;
if ((n & tuple) == 0)
return n + lastBit;
return -(n + lastBit);
}
我最初的方法是使用最后一位作为检查位,以了解我们在第一次或第二次调用中的位置。基本上,我会在第一次调用后将此位设置为1,以向第二次调用发出第一次调用已经通过的信号。但是,这种方法被负数所击败,负数的最后一位在第一次调用期间已经到达1。
同样的理论适用于大多数负数的倒数第二位。但是,通常发生的情况是,大多数情况下,最后一位和第二位是相同的。它们要么都是负数的1,要么都是正数的0。
所以我的最后一个方法是检查它们是否都是1或都是0,这意味着在大多数情况下这是第一次调用。如果最后一位与第二个最后一位不同,那么我假设我们在第二次调用,然后简单地重新反转最后一位。显然,对于使用最后两位的非常大的数字来说,这不起作用。但是,它再次适用于非常广泛的数字。
这个问题并没有说明函数f的输入类型和返回值必须是什么(至少不是你给出的方式)。。。
…只是当n是32位整数时,f(f(n))=-n
那么,怎么样
Int64 f(Int64 n)
{
return(n > Int32.MaxValue ?
-(n - 4L * Int32.MaxValue):
n + 4L * Int32.MaxValue);
}
如果n是32位整数,则语句f(f(n))==-n将为真。
显然,这种方法可以扩展到更大范围的数字。。。