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

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

有什么想法吗?


当前回答

除int.MaxValue和int.MinValue以外的工作

    public static int f(int x)
    {

        if (x == 0) return 0;

        if ((x % 2) != 0)
            return x * -1 + (-1 *x) / (Math.Abs(x));
        else
            return x - x / (Math.Abs(x));
    }

其他回答

使用复数,您可以有效地将否定数字的任务分为两个步骤:

将n乘以i,得到n*i,n逆时针旋转90°再乘以i,得到-n

最棒的是,您不需要任何特殊的处理代码。只要乘以i就可以了。

但不允许使用复数。因此,您必须使用部分数据范围创建自己的虚拟轴。由于需要的虚(中间)值与初始值一样多,因此只剩下一半的数据范围。

我试图在下图中显示这一点,假设有符号的8位数据。您必须将其缩放为32位整数。初始n的允许范围为-64到+63。下面是函数对正n的作用:

如果n在0..63(初始范围)内,函数调用将添加64,将n映射到范围64..127(中间范围)如果n在64..127(中间范围)内,则函数从64中减去n,将n映射到范围0..-63

对于负n,函数使用中间范围-65..-128。

我有另一个解决方案,它可以在一半时间内工作:

def f(x):
    if random.randrange(0, 2):
        return -x
    return x

虽然问题说n必须是32位int,但它没有说参数或返回类型必须是32比特int0

private final long MAGIC_BIT=1<<38;
long f(long n) {
    return n & MAGIC_BIT != 0 ? -(n & !MAGIC_BIT) : n | MAGIC_BIT;
}

编辑:

这实际上是一个很好的面试问题。最好的答案是难以或不可能回答的,因为它迫使人们仔细思考,你可以观察并寻找:

他们会放弃吗?他们说这很愚蠢吗?他们是否尝试独特的方法?他们在处理问题时是否与您沟通?他们是否要求进一步细化要求?

etc.

永远不要只回答行为问题,除非你有一个非常好的答案。始终保持愉快,并尝试让提问者参与进来。不要沮丧,不要过早放弃!如果你真的一无所获,尝试一些完全非法的、可能奏效的方法,你将获得几乎全部的学分。

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

我认为这些问题的答案最好用图表直观地解释。当我们忽略零时,我们可以将整数分成4个数的小集合:

 1  → 2    3  → 4    5  → 6
 ↑    ↓    ↑    ↓    ↑    ↓   ...
-2 ← -1   -4 ← -3   -6 ← -5

这很容易翻译成代码。注意,偶数改变符号,奇数增加或减少1。在C#中,它看起来像这样:

public static int f(int x)
{
    if(x == 0)
        return 0;

    if(x > 0)
        return (x % 2 == 0) ? -x+1 : x+1;

    // we know x is negative at this point
    return (x % 2 == 0) ? -x-1 : x-1;
}

当然,您可以通过使用巧妙的技巧来缩短此方法,但我认为这段代码最好地解释了它本身。

然后是范围。32位整数的范围从-2^31到2^31-1。数字2^31-1、-2^31-1和-2^31超出了f(x)的范围,因为缺少数字2^31。