我在上次面试中遇到的一个问题是:

设计函数f,使得:f(f(n))==-n其中n是32位有符号整数;你不能用复数算术。如果你不能为整个数字范围设计这样的函数,那么就尽可能为最大范围设计它。

有什么想法吗?


当前回答

int func(int a)  
{   
    static int p = 0;  
    int ret = a;  

    if ( p ) ret *= -1;  
    p ^= 1;  

    return ret;  
}  

其他回答

f(x)=在二维笛卡尔坐标系中围绕原点逆时针旋转90度的点(x)。仅一个数字x的输入被假定为(x,0),并且具有y=0的输出被提供为单个数字x。

object f: (object) x {
    if (x.length == 1)
        x = (x, 0)
    swap = x[0]
    x[1] = x[0]
    x[0] = -swap
    if (x[1] == 0)
        x = x[0]
    return x

x86 asm(AT&T风格):

; input %edi
; output %eax
; clobbered regs: %ecx, %edx
f:
    testl   %edi, %edi
    je  .zero

    movl    %edi, %eax
    movl    $1, %ecx
    movl    %edi, %edx
    andl    $1, %eax
    addl    %eax, %eax
    subl    %eax, %ecx
    xorl    %eax, %eax
    testl   %edi, %edi
    setg    %al
    shrl    $31, %edx
    subl    %edx, %eax
    imull   %ecx, %eax
    subl    %eax, %edi
    movl    %edi, %eax
    imull   %ecx, %eax
.zero:
    xorl    %eax, %eax
    ret

代码已检查,所有可能的32位整数都已通过,错误为-2147483647(下溢)。

根据您的平台,某些语言允许您在函数中保持状态。VB.Net,例如:

Function f(ByVal n As Integer) As Integer
    Static flag As Integer = -1
    flag *= -1

    Return n * flag
End Function

IIRC、C++也允许这样做。我怀疑他们正在寻找不同的解决方案。

另一个想法是,由于它们没有定义函数第一次调用的结果,因此可以使用奇数/均匀度来控制是否反转符号:

int f(int n)
{
   int sign = n>=0?1:-1;
   if (abs(n)%2 == 0)
      return ((abs(n)+1)*sign * -1;
   else
      return (abs(n)-1)*sign;
}

所有偶数的幅度加一,所有奇数的幅度减一。两次调用的结果大小相同,但在一次调用中,我们甚至交换了符号。在某些情况下,这不会起作用(-1,max或min int),但它的效果比迄今为止任何其他建议都要好得多。

这很简单!

每个数字以4为周期映射到另一个数字,其中所需条件成立。

例子:

规则如下:

0→ 0±2³¹ → ±2³¹古怪的→ 甚至,甚至→ -奇数:对于所有k,0<k<2³⁰: (2k-1)→ (2k)→ (-2k+1)→ (-2k)→ (2k-1)

唯一不匹配的值是±(2³¹-1),因为只有两个。必须有两个不能匹配,因为在二进制补码系统中只有四个数字的倍数,其中0和±2³¹已被保留。

在一的补码系统中,存在+0和-0。我们开始了:

对于所有k,0<k<2³⁰: (+2k)→ (+2k+1)→ (-2k)→ (-2k-1)→ (+2k)

我希望你改变2个最高有效位。

00.... => 01.... => 10.....

01.... => 10.... => 11.....

10.... => 11.... => 00.....

11.... => 00.... => 01.....

正如你所看到的,这只是一个补充,省去了进位。

我是怎么得到答案的?我的第一个想法就是需要对称。4转回到我开始的地方。起初我想,这是20比特的格雷码。然后我觉得标准二进制就足够了。