我在上次面试中遇到的一个问题是:
设计函数f,使得:f(f(n))==-n其中n是32位有符号整数;你不能用复数算术。如果你不能为整个数字范围设计这样的函数,那么就尽可能为最大范围设计它。
有什么想法吗?
我在上次面试中遇到的一个问题是:
设计函数f,使得:f(f(n))==-n其中n是32位有符号整数;你不能用复数算术。如果你不能为整个数字范围设计这样的函数,那么就尽可能为最大范围设计它。
有什么想法吗?
当前回答
另一种利用短路的Javascript解决方案。
function f(n) {return n.inv || {inv:-n}}
f(f(1)) => -1
f(f(-1)) => 1
其他回答
在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 -abs(n);
}
这里有一个证明,如果不使用额外信息(除了32位的int),那么对于所有数字,这样的函数都不可能存在:
我们必须使f(0)=0。(证明:假设f(0)=x,则f(x)=f(f(0))=-0=0。现在,-x=f(f(x))=f(0)=x,这意味着x=0。)
此外,对于任何x和y,假设f(x)=y。那么我们希望f(y)=-x。并且f(f(y))=-y=>f(-x)=-y。总结一下:如果f(x)=y,那么f(-x)=-y,f(y)=-x,f(-y)=x。
因此,我们需要将除0之外的所有整数分成4个集合,但我们有奇数个这样的整数;不仅如此,如果我们去掉没有正对应的整数,我们仍然有2(mod4)个数。
如果我们去掉剩下的2个最大数(通过abs值),我们可以得到函数:
int sign(int n)
{
if(n>0)
return 1;
else
return -1;
}
int f(int n)
{
if(n==0) return 0;
switch(abs(n)%2)
{
case 1:
return sign(n)*(abs(n)+1);
case 0:
return -sign(n)*(abs(n)-1);
}
}
当然,另一种选择是不遵守0,并获得我们删除的2个数字作为奖励。(但这只是一个愚蠢的假设。)
对于所有32位值(注意,-0是-2147483648)
int rotate(int x)
{
static const int split = INT_MAX / 2 + 1;
static const int negativeSplit = INT_MIN / 2 + 1;
if (x == INT_MAX)
return INT_MIN;
if (x == INT_MIN)
return x + 1;
if (x >= split)
return x + 1 - INT_MIN;
if (x >= 0)
return INT_MAX - x;
if (x >= negativeSplit)
return INT_MIN - x + 1;
return split -(negativeSplit - x);
}
基本上需要将每个-x=>x=>-x循环与y=>-y=>y循环配对。所以我把裂口的两边配对。
例如,对于4位整数:
0 => 7 => -8 => -7 => 0
1 => 6 => -1 => -6 => 1
2 => 5 => -2 => -5 => 2
3 => 4 => -3 => -4 => 3
我希望你改变2个最高有效位。
00.... => 01.... => 10.....
01.... => 10.... => 11.....
10.... => 11.... => 00.....
11.... => 00.... => 01.....
正如你所看到的,这只是一个补充,省去了进位。
我是怎么得到答案的?我的第一个想法就是需要对称。4转回到我开始的地方。起初我想,这是20比特的格雷码。然后我觉得标准二进制就足够了。