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

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

有什么想法吗?


当前回答

我认为这些问题的答案最好用图表直观地解释。当我们忽略零时,我们可以将整数分成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。

其他回答

少于50个字符(C#)

int f(int n) { return (n <= 0) ? n : f(-n); }

或更容易阅读:

static int f(int n) { 
  if (n <= 0)
    return n;
  else 
    return f(-n);
}

要测试

static void Main(string[] args) {
    for (int n = int.MinValue; n < int.MaxValue; n+=1) {
        Console.Out.WriteLine("Value: " + n + " Result: " + f(f(n)));
    }
}

它有效(假设我正确理解问题)

int f(int n)
{
   static int x = 0;
   result = -x;
   x = n;
   return result;
}

这是一个带有否定的单条目FIFO。当然,它不适用于最大负数。

创建许多解的一种方法是注意,如果我们将整数划分为两个集合S和R

那么我们可以如下创建f:

如果x在R中,则f(x)=g(x)

如果x在S中,则f(x)=-invg(x)

其中invg(g(x))=x,所以invg是g的逆函数。

上面提到的第一个解决方案是分区R=偶数,R=奇数,g(x)=x+1。

我们可以取任意两个无限集合T,P s.T T+U=整数集合,取s=T+(-T),R=U+(-U)。

然后-S=S和-R=R通过它们的定义,我们可以将g取为从S到R的任何1-1对应关系,这必须存在,因为这两个集合都是无限的和可数的。

因此,这将为我们提供许多解决方案,但并非所有解决方案都可以编程,因为它们不会被有限地定义。

例如:

R=可被3整除的数字,S=不可被3除的数字。

然后我们取g(6r)=3r+1,g(6r+3)=3r+2。

我认为这些问题的答案最好用图表直观地解释。当我们忽略零时,我们可以将整数分成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。

我不知道这是否完全正确,但一个简单的标志不起作用吗?在C语言中,使用静态局部变量,我成功地做到了这一点:

int main()
{
    int n = -256; // 32-bit signed integer
    printf("%d", f(f(n)));
}

int f(int n){
    static int x = 0; // not returning negative;
    switch(x){
        case 0:
            x = 1;
            return n;
            break;

        case 1:
            x = 0;
            return -n;
            break;
        default:
            return -999;
            break;
    }
}