【问题标题】:Designing function f(f(n)) == -n设计函数 f(f(n)) == -n
【发布时间】:2010-10-18 10:12:31
【问题描述】:

我上次面试时遇到的一个问题:

设计一个函数f,这样:

f(f(n)) == -n

n 是一个 32 位 有符号整数;你不能使用复数算术。

如果您无法为整个数字范围设计这样的函数,请尽可能设计最大范围。

有什么想法吗?

【问题讨论】:

  • 这次面试是为了什么工作?

标签: math integer


【解决方案1】:

Tcl:

proc f {input} {
    if { [string is integer $input] } {
      return [list expr [list 0 - $input]]
    } else {
      return [eval $input]
    }
}

% f [f 1]
-1

按照其他一些答案的思路...如果它是一个整数,则返回一个返回该数字的负数的命令。如果不是数字,则对其求值并返回结果。

【讨论】:

    【解决方案2】:

    这是一个 C/C++ 解决方案,不使用任何位运算符,也不需要任何数学库,尽管它有点作弊......

    double f(double n)
    {
        if (n == (double)(int)n)
            return n + 0.5;
        else
            return -(n - 0.5);
    }
    

    这适用于所有 32 位整数,但 0x80000000 是一个例外(因为它的反面不能存储在 32 位整数系统中)。 f(f(n)) == -n 将始终为 true,除非在这种情况下。

    不过,我确信有一种更简单、更快捷的方法来实现它。这只是浮现在脑海中的第一件事。

    【讨论】:

      【解决方案3】:
      int func(int a)  
      {   
          static int p = 0;  
          int ret = a;  
      
          if ( p ) ret *= -1;  
          p ^= 1;  
      
          return ret;  
      }  
      

      【讨论】:

        【解决方案4】:

        这个想法已经在其他答案中使用过,但我在一行 Python 中得到了它:

        def f(n):
            return str(n) if type(n) == int else -int(n)
        

        【讨论】:

          【解决方案5】:
          int f(int n)
          {
            static long counter=0;
            counter++;
            if(counter%2==0)
              return -n;
            else
              return n;
          }
          

          【讨论】:

            【解决方案6】:
            #include <cmath>
            
            int f(int n)
            {
                static int count = 0;
                return ::cos(M_PI * count++) * n;
            }
            

            【讨论】:

            • 应该注意,这可能会给多线程环境带来问题。
            【解决方案7】:

            SQL Server 中的解决方案

            create function dbo.fn_fo(@num int) -- OUTER FUNCTION
            RETURNS int
            AS
            begin
            RETURN @num * -1
            end
            GO
            
            create function dbo.fn_fi(@num int) -- INNER FUNCTION
            RETURNS int
            AS
            begin
            RETURN @num * -1
            end
            GO
            
            declare @num AS int = -42
            SELECT dbo.fn_fo(dbo.fn_fi(@num)) -- Gives (-42)
            

            【讨论】:

              【解决方案8】:

              也许我遗漏了什么?

              这不就是这么简单吗:

                  function f(n)
                  {
                      if(n ==0 || n < 0){return n;}
                      return n * -1;
                  }
              

              编辑:

              所以我错过了这个问题,哼哼,所以:

                  function f(n)
                  {
                      if(!c(n,"z")&&!c(n,"n")){if(n==0){return "z"+n;}return "n"+n;}
                      if( c(n,"z")){return 0;}return parseInt(n.replace("n",""))*-1;
                  }
                  function c(x,y){return x.indexOf(y) !==-1;}
              

              丑陋但有效。

              【讨论】:

              • -1 的答案应该是什么?
              • 问题不是关于 f(n),而是关于 f(f(n))。 f(f(-1)) 应该返回 1,您的解决方案将返回 -1
              • 这取决于你如何解释这个问题?
              • 不,它没有。您的函数计算 f(f(-1)) = -1,但需要 1。
              • 需求为f(f(n)) = -n。现在替换 n=-1。因此 f(f(-1)) 应该是 -(-1),即 1。那里没有什么可以解释的。
              【解决方案9】:

              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
              

              【讨论】:

              • 它是哪种编程语言?
              • "其中 n 是一个 32 位 有符号整数;您不能使用复数算术。"
              • @Mask:这是伪代码。可以轻松翻译成任何语言。
              • @Zecc:我认为您不了解“复数算术”的概念。我发布的代码没有使用数学意义上的复杂数学 - 也不是口语意义上的:理解和应用非常简单。
              • @DavidStein 是的,我知道。我引用太多,评论太少,对此我深表歉意。我的意思是 x 应该是一个 32 位有符号整数。现在我意识到这就是为什么你要开始测试x.length == 1。伪代码把我吓跑了。
              【解决方案10】:

              我承认我会作弊,但仍然符合要求。这是编程魔法,而不是真正的数学。它适用于整个范围,除了 -2^31。

              int f(int n)
              {
                  static bool eFlag = false; // Only executed once
                  eFlag = !eFlag;
                  return eFlag?-n:n;
              }
              

              【讨论】:

                【解决方案11】:

                C++ 中的另一种作弊解决方案,运算符重载。

                struct func {
                    int n;
                    func operator()(int k) { n = -k; return *this; }
                    int operator()(const func &inst) { return inst.n; }
                } f;
                

                【讨论】:

                  【解决方案12】:

                  我不知道这是否完全正确,但是一个简单的标志就不会起作用吗?在 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;
                      }
                  }
                  

                  【讨论】:

                  • 我认为这行不通。 f(3) 返回 3 然后 f(4) 返回 -4
                  【解决方案13】:

                  Objective-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 逻辑存储在数字为奇数或偶数的状态下。

                  【讨论】:

                    【解决方案14】:

                    f# 中的简单解决方案(不使用“技巧”)

                    let rec f n =
                        if n = 0 then 0
                        elif n > 0 then
                            if (f (n - 1) <> n) then n + 1
                            else -(n - 1)
                        else
                            if (f (-(n - 1)) = n) then n - 1
                            else -(n + 1) 
                    

                    【讨论】:

                      【解决方案15】:

                      F#

                      let f n =
                          match n with
                          | n when n % 2 = 0 -> -n + System.Math.Sign n
                          | _ -> n - System.Math.Sign -n
                      

                      其中n 使得System.Int32.MinValue &lt; n &lt; System.Int32.MaxValue

                      【讨论】:

                        【解决方案16】:

                        我尝试打高尔夫球 this answer Rodrick Chapman

                        无分支:74 个字符

                        int f(int i){return(-((i&1)<<1)|1)*i-(-((i>>>31)<<1)|1)*(((i|-i)>>31)&1);}
                        

                        带有分支,Java 风格:58 个字符

                        int f(int i){return i==0?0:(((i&1)==0?i:-i)+(i>0?-1:1));}
                        

                        带有分支,C 风格:52 个字符

                        int f(int i){return i?(((i&1)?-i:i)+(i>0?-1:1)):0;}
                        

                        经过快速但有效的基准测试后,分支版本在我的机器上的速度提高了 33%。 (正数和负数的随机数据集,足够的重复并阻止编译器优化代码,并进行预热。)这并不奇怪,考虑到非分支版本中的操作数量和可能的良好分支预测,因为事实上该函数被调用两次:f(f(i))。当我将基准更改为测量:f(i) 时,分支版本仅快 28%。我认为这证明了分支预测在第一种情况下确实做了一些好事。更多证明:使用f(f(f(f(i)))) 进行测试时,分支版本的速度提高了 42%。

                        【讨论】:

                          【解决方案17】:

                          Wolfram Language中的解决方案:

                          f[f[n_]] := -n
                          

                          应用:

                          In[2]:= f[f[10]]                                                                                                                                                                                                                                                                              
                          Out[2]= -10
                          In[3]:= f[10]                                                                                                                                                                                                                                                                                 
                          Out[3]= f[10]
                          

                          因为问题没有说明 f(n) 的值,所以 f[n] 仍未计算。

                          【讨论】:

                            【解决方案18】:

                            Javascript

                            function f(n)  { 
                                    return typeof n === "number" ? 
                                    function() {return -n} : 
                                    n();
                            }
                            

                            【讨论】:

                              【解决方案19】:

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

                              受@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的最左边两位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]

                              【讨论】:

                                【解决方案20】:
                                int f(int x){
                                    if (x < 0)
                                        return x;
                                    return ~x+1; //two's complement
                                }
                                

                                【讨论】:

                                • -1 失败。 f(f(-1)) 应该是 -(-1) 即 +1,但你的结果是 -1。
                                【解决方案21】:

                                PHP,不使用全局变量:

                                function f($num) {
                                  static $mem;
                                
                                  $answer = $num-$mem;
                                
                                  if ($mem == 0) {
                                    $mem = $num*2;
                                  } else {
                                    $mem = 0;
                                  }
                                
                                  return $answer;
                                }
                                

                                适用于整数、浮点数和数字字符串!

                                刚刚意识到这做了一些不必要的工作,但是,无论如何

                                【讨论】:

                                  【解决方案22】:

                                  记住你最后的状态不是一个足够好的答案吗?

                                  int f (int n)
                                  {
                                      //if count 
                                      static int count = 0;
                                  
                                      if (count == 0)
                                          { 
                                              count = 1;
                                              return n;
                                          }
                                  
                                      if (n == 0)
                                          return 0;
                                      else if (n > 0)
                                      {
                                          count = 0;
                                          return abs(n)*(-1);
                                      } 
                                      else
                                      {
                                          count = 0;
                                          return abs(n);
                                      }
                                  }
                                  
                                  int main()
                                  {
                                      int n = 42;
                                      std::cout << f(f(n))
                                  }
                                  

                                  【讨论】:

                                  • 取决于面试官对“功能”的定义。那是一种方法——一个函数实际上没有状态。但也许他们并不是字面上的意思。
                                  • 表达状态不是线程安全的,而且过于复杂!= state
                                  【解决方案23】:

                                  我认为可能的最大范围暗示了一种模算术解决方案。在一些模基 M 中,有一个数在平方时与 M-1 一致(与 -1 一致)。例如,如果 M=13, 5*5=25, 25 mod 13=12 (= -1)
                                  不管怎样,这里有一些 M=2**32-3 的 python 代码。

                                  def f(x):
                                      m=2**32-3;
                                      halfm=m//2;
                                      i_mod_m=1849436465
                                      if abs( x ) >halfm:
                                          raise "too big"
                                      if x<0:
                                          x+=m
                                      x=(i_mod_m*x) % m
                                      if (x>halfm):
                                          x-=m
                                      return x;
                                  

                                  请注意,有 3 个值不适用于 2 ** 31-1、-(2 ** 31-1) 和 -(2 ** 31)

                                  【讨论】:

                                    【解决方案24】:

                                    它通过保存状态来作弊,但它有效,将操作分成两部分:-n = (~n + 1) 用于整数

                                    int f(int n) {
                                        static int a = 1;
                                        a = !a;
                                        if (a) {
                                            return (~n);
                                        } else {
                                            return (n+1);
                                        }
                                    }
                                    

                                    【讨论】:

                                      【解决方案25】:

                                      使用循环置换方法来做到这一点。

                                      -b a b -a

                                      a b -a -b

                                      在琐碎的情况下 f(0) 返回 0

                                      抱歉我的电话粗略回答,28 日之后我会发布完整版(正在考试中...) 简单地说,认为f(n)是一个循环置换,问题是如何构造它。

                                      定义 fk = f(f(f(f(...f(n))))) (k fs) 情况 k=2 0.琐碎的情况 f(0) 返回 0 1. 分组,在 k=2 的情况下,分组: {0} {1,2} {3,4} ... {n,n+1 | (n+1)%2 = 0 } ,注意:我只使用 Z+,因为构造不需要使用负数。 2.构造排列: 如果 n % 2 = 0,那么 a=n-1 b=n 如果 n % 2 = 1,那么 a=n b=n+1

                                      这将产生相同的排列,因为 n 和 f(n) 在同一个组中。

                                      注意排列为 P 返回 P(n)

                                      对于 k=2t ,只做上面相同的事情,只是 MOD k。 对于k=2t-1,虽然方法行得通,但是没有意义,啊? (f(n) = -n 没问题)

                                      【讨论】:

                                        【解决方案26】:

                                        我还没有查看其他答案,我认为按位技术已经被彻底讨论过。

                                        我以为我会在 C++ 中想出一些邪恶的东西,希望不是骗子:

                                        struct ImplicitlyConvertibleToInt
                                        {
                                            operator int () const { return 0; }
                                        };
                                        
                                        int f(const ImplicitlyConvertibleToInt &) { return 0; }
                                        
                                        ImplicitlyConvertibleToInt f(int & n)
                                        {
                                            n = 0; // The problem specification didn't say n was const
                                            return ImplicitlyConvertibleToInt();
                                        }
                                        

                                        整个ImplicitlyConvertibleToInt 类型和重载是必要的,因为临时对象不能绑定到非常量引用。

                                        当然,现在看是不确定f(n)是否在-n之前执行。

                                        对于这种程度的邪恶,也许更好的解决方案是:

                                        struct ComparesTrueToInt
                                        {
                                            ComparesTrueToInt(int) { } // implicit construction from int
                                        };
                                        bool operator == (ComparesTrueToInt, int) const { return true; }
                                        
                                        ComparesTrueToInt f(ComparesTrueToInt ct) { return ComparesTrueToInt(); }
                                        

                                        【讨论】:

                                        • C++ 因为像你这样的人而声名狼藉。这是一种可怕的做法......虽然它在一定程度上解决了比较f(f(x)) == -x,但它对于任何其他用途都是完全无用和破坏性的。你说得对,它是邪恶的;但这绝不是一件好事。此外...如果有人像这样测试您的功能,您会怎么做:cout &lt;&lt; x &lt;&lt; (f(f(x)) == -x ? " works." : " doesn't work.") &lt;&lt; endl; 结果未定义。在我的 GCC 版本中,它每行打印零。被当场抓获!
                                        【解决方案27】:

                                        少于 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)));
                                            }
                                        }
                                        

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

                                        【讨论】:

                                        • 这仅在n 最初为正(或零)时有效。问题明确指出Where n is a 32 bit *signed integer*,这意味着 n 也可以从否定开始。
                                        【解决方案28】:

                                        怎么样

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

                                        【讨论】:

                                        • 好吧,您只需要指定它仅适用于正整数 (0
                                        猜你喜欢
                                        • 2015-08-13
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 2015-10-08
                                        • 1970-01-01
                                        • 1970-01-01
                                        • 1970-01-01
                                        相关资源
                                        最近更新 更多