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

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

有什么想法吗?


当前回答

这很简单!

每个数字以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)

其他回答

有些类似,但我只是想写下我的第一个想法(用C++)

#include <vector>

vector<int>* f(int n)
{
  returnVector = new vector<int>();
  returnVector->push_back(n);
  return returnVector;
}

int f(vector<int>* n) { return -(n->at(0)); }

仅使用重载使f(f(n))实际调用两个不同的函数

目标-C

这适用于除“-1”以外的所有数字。

如果要从使用int转换为使用NSInt,那么可以将-1值设置为NULL,然后第二次将它们转换为+1,但我觉得NSInt欺骗了询问者的意图。


f(n):

-(int)f:(int)n {
    if (abs(n)==1) {
        n = -1;
    } else {
        if (abs(n)%2) {//o
            if (n>0) {//+
                n--;
                n*=+1;
            } else if (n<0) {//-
                n++;
                n*=+1;
            }
        } else {//e
            if (n>0) {//+
                n++;
                n*=-1;
            } else if (n<0) {//-
                n--;
                n*=-1;
            }
        }
    }
    return n;
}

当然,这一切都可以缩短为一行,但其他人可能无法阅读。。。

无论如何,我将BOOLEAN逻辑存储为奇数或偶数的状态。

斯卡拉:

def f(x: Any): Any = x match {
  case i: Int => new { override def hashCode = -i }
  case i @ _  => i.hashCode
}

在Java中也是如此:

public static Object f(final Object x) {
  if(x instanceof Integer) {
    return new Object() {
      @Override 
      public int hashCode() {
        return -(Integer)x;
      }
    };
  }
  return x.hashCode();
}

简单的Python解决方案之所以成为可能,是因为对f(x)应该输出的内容没有限制,只有f(f(x)):

def f(x):
    return (isinstance(x, tuple) and -x[0]) or (x,)

根据您的平台,某些语言允许您在函数中保持状态。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),但它的效果比迄今为止任何其他建议都要好得多。