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

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

有什么想法吗?


当前回答

return x ^ ((x%2) ? 1 : -INT_MAX);

其他回答

根据微软/谷歌的面试官通常在面试中提出的问题,我认为提问者指的是一种创新、轻量级、简单的解决方案,它将使用按位操作,而不是那些复杂的高级答案。

灵感来自@eipipuz的回答,我编写了这个C++函数(但没有运行它):

int32_t f(int32_t n){
    int32_t temp = n & 00111111111111111111111111111111;
    x = n >> 30;
    x++;
    x = x << 30;
    return x | temp;
}

它将n的最左边的两位存储在x中,将x加1,然后再次将其替换为n的最左侧的两位。

如果我们继续以另一个f(n)作为参数n运行f(n,则最左边的两个位将如下旋转:

00 --> 01 --> 10 --> 11 --> 00 ...

请注意,最右边的30位不变。8位整数示例:

示例1:

>f(00001111)=01001111>f(01001111)=10001111[这是原始值的负值,00001111]

示例2:

>f(11101010)=00101010>f(00101010)=01101010[这是原始值11101010的负值]

我参加这个聚会迟到了,现在可能是墓地了。但我有两个贡献,灵感来自viraptor先前使用lambda的Python答案。读者可能认为该解决方案仅在非类型化语言中可行,而在类型化语言中将需要一些明确的额外标记。

但下面是Haskell中的解决方案1(我不是Haskell专家)。它有点作弊,因为从技术上讲,两个f是两个不同的实现。(一个f::Int->()->Int,另一个f::(()->Int)->Int)

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FunctionalDependencies #-}

module Main where

class Tran σ τ | σ -> τ where
  tran :: σ -> τ

instance Tran Int (() -> Int) where
  tran n = \_ -> (-n)

instance Tran (() -> Int) Int where
  tran g = g ()

f :: Tran σ τ => σ -> τ
f = tran

main :: IO ()
main = do
  print $ f (f (42 :: Int)) -- --> -42
  print $ f (f (0 :: Int)) -- --> 0
  print $ f (f (-69 :: Int)) -- --> 69

接下来是Typed Racket中的解决方案2。这一个满足了最大可能域的属性,因为Racket中的Number最多包含复数:

#lang typed/racket

(: f (case->
      [Number -> (-> Number)]
      [(-> Number) -> Number]))
(define (f x)
  (if (number? x) (λ () (- x)) (x)))

(f (f 42))    ; --> -42
(f (f 0))     ; --> 0
(f (f -69))   ; --> 69
(f (f 3/4))   ; --> -3/4
(f (f 8+7i))  ; --> -8-7i

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

斯卡拉:

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();
}

怎么样

int f(int n)
{
    return -abs(n);
}