提问人: 提问时间:4/9/2009 最后编辑:13 revs, 9 users 27%Gumbo 更新时间:8/13/2022 访问量:84587
设计函数 f(f(n)) == -n
Designing function f(f(n)) == -n
问:
我在上次面试中遇到的一个问题:
设计一个函数,使得:
f
f(f(n)) == -n
其中是 32 位有符号整数;不能使用复数算术。
n
如果无法为整个数字范围设计这样的函数,请将其设计为尽可能大的范围。
有什么想法吗?
答:
所有负数都是如此。
f(n) = abs(n)
因为对于二进制补码整数,负数比正数多一个,所以比与 相同的解多一个情况有效。把你弄到一个... :Df(n) = abs(n)
f(n) = n > 0 ? -n : n
f(n) = -abs(n)
更新
不,它对另一种情况无效,因为我刚刚通过 litb 的评论认识到...... 只会溢出......abs(Int.Min)
我也考虑过使用 mod 2 信息,但得出的结论是,它不起作用......到早期。如果操作得当,它将适用于所有数字,除非这会溢出。Int.Min
更新
我玩了一段时间,寻找一个不错的操作技巧,但我找不到一个好的单行,而 mod 2 解决方案适合其中之一。
f(n) = 2n(abs(n) % 2) - n + sgn(n)
在 C# 中,这将变为以下内容:
public static Int32 f(Int32 n)
{
return 2 * n * (Math.Abs(n) % 2) - n + Math.Sign(n);
}
要使它适用于所有值,您必须将计算替换为块并将其包含在块中。然后你甚至会像未经检查的否定一样映射到自己。Math.Abs()
(n > 0) ? +n : -n
unchecked
Int.Min
更新
受到另一个答案的启发,我将解释该函数的工作原理以及如何构造这样的函数。
让我们从头开始。该函数被重复应用于给定值,从而产生一系列值。f
n
n => f(n) => f(f(n)) => f(f(f(n))) => f(f(f(f(n)))) => ...
问题要求,即否定论证的两次连续应用。另外两个应用(总共四个)再次否定了该论点,再次产生。f(f(n)) = -n
f
f
n
n => f(n) => -n => f(f(f(n))) => n => f(n) => ...
现在有一个明显的长度四的循环。代入并注意得到的方程成立,得到以下结果。x = f(n)
f(f(f(n))) = f(f(x)) = -x
n => x => -n => -x => n => ...
因此,我们得到一个长度为四的循环,其中有两个数字,两个数字被否定。如果将循环想象为矩形,则否定值位于相对的角处。
构建这种循环的众多解决方案之一是从 n 开始的以下解决方案。
n => negate and subtract one -n - 1 = -(n + 1) => add one -n => negate and add one n + 1 => subtract one n
这种循环的一个具体例子是。我们快完成了。注意到构造的循环包含一个奇数正数,它的偶数后继数,并且两个数都否定,我们可以轻松地将整数划分为许多这样的循环(是 4 的倍数),并找到了满足条件的函数。+1 => -2 => -1 => +2 => +1
2^32
但是我们有一个零的问题。循环必须包含,因为零本身被否定。而且因为循环状态已经存在,所以它遵循.这只是一个长度为二的循环,并且在两次应用后变成它自己,而不是变成 .幸运的是,有一个案例可以解决这个问题。如果等于零,我们得到一个长度为 1 的循环,其中只包含零,我们解决了这个问题,得出的结论是零是 的不动点。0 => x => 0
0 => x
0 => x => 0 => x
x
-x
X
f
做?几乎。我们有数字,零是留下数字的不动点,我们必须将该数字划分为四个数字的循环。不好的是,这不是 4 的倍数 - 将剩下三个数字,而不是在任何长度为 4 的循环中。2^32
2^32 - 1
2^32 - 1
我将使用较小的 3 位有符号迭代器集来解释解决方案的其余部分,范围从 到 。我们完成了零。我们有一个完整的周期。现在让我们从 .-4
+3
+1 => -2 => -1 => +2 => +1
+3
+3 => -4 => -3 => +4 => +3
出现的问题是不能表示为 3 位整数。我们将通过否定 - 仍然是一个有效的 3 位整数 - 但随后将一个添加到 (二进制) 会产生二进制。它被解释为无符号整数,但我们必须将其解释为有符号整数。因此,实际上对于这个例子,或者在一般情况下,是整数算术否定的第二个不动点 - 并且映射到它们本身。所以循环其实是这样的。+4
+4
-3
+3
+3
011
100
+4
-4
-4
Int.MinValue
0
Int.MinValue
+3 => -4 => -3 => -4 => -3
它是一个长度为二的循环,另外通过 进入循环。因此,在两个函数应用程序之后被正确映射到自身,在两个函数应用程序之后被正确映射到自身,但在两个函数应用程序之后被错误地映射到自身。+3
-4
-4
+3
-3
-3
因此,我们构造了一个函数,该函数适用于除一个整数之外的所有整数。我们能做得更好吗?不,我们不能。为什么?我们必须构造长度为 4 的周期,并且能够覆盖最多四个值的整个整数范围。其余值是两个固定点,必须映射到它们自身和两个任意整数,并且必须由两个函数应用程序相互映射。0
Int.MinValue
x
-x
要映射到,反之亦然,它们必须形成一个四个循环,并且它们必须位于该循环的相对角。因此,也必须处于对立的角落。这将正确映射,但在两个函数应用程序之后交换两个固定点,并给我们留下两个失败的输入。因此,不可能构造一个适用于所有值的函数,但我们有一个适用于除一个值之外的所有值的函数,这是我们能实现的最好的函数。x
-x
0
Int.MinValue
x
-x
0
Int.MinValue
评论
根据您的平台,某些语言允许您在函数中保留状态。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,从所有奇数的大小中减去 1。两次调用的结果具有相同的大小,但一次调用甚至我们交换符号。在某些情况下,这不起作用(-1、max 或 min int),但它比迄今为止建议的任何其他方法都要好得多。
评论
我可以想象使用第 31 位作为假想 (i) 位将是一种支持总范围一半的方法。
评论
适用于 n= [0 .. 2^31-1]
int f(int n) {
if (n & (1 << 31)) // highest bit set?
return -(n & ~(1 << 31)); // return negative of original n
else
return n | (1 << 31); // return n with highest bit set
}
怎么样:
f(n) = sign(n) - (-1)ⁿ * n
在 Python 中:
def f(n):
if n == 0: return 0
if n >= 0:
if n % 2 == 1:
return n + 1
else:
return -1 * (n - 1)
else:
if n % 2 == 1:
return n - 1
else:
return -1 * (n + 1)
Python 会自动将整数提升为任意长度的长整型。在其他语言中,最大的正整数将溢出,因此它适用于除该整数之外的所有整数。
要使它适用于实数,您需要将 (-1)ⁿ 中的 n 替换为 。{ ceiling(n) if n>0; floor(n) if n<0 }
在 C# 中(适用于任何双精度值,溢出情况除外):
static double F(double n)
{
if (n == 0) return 0;
if (n < 0)
return ((long)Math.Ceiling(n) % 2 == 0) ? (n + 1) : (-1 * (n - 1));
else
return ((long)Math.Floor(n) % 2 == 0) ? (n - 1) : (-1 * (n + 1));
}
评论
这个问题没有说明函数 f
的输入类型和返回值必须是什么(至少不是你呈现它的方式)......
...只是当 n 是 32 位整数时f(f(n)) = -n
那么,像这样的东西怎么样
Int64 f(Int64 n)
{
return(n > Int32.MaxValue ?
-(n - 4L * Int32.MaxValue):
n + 4L * Int32.MaxValue);
}
如果 n 是 32 位整数,则该语句将为 true。f(f(n)) == -n
显然,这种方法可以扩展到更广泛的数字......
评论
在MIN_INT上不会失败:
int f(n) { return n < 0 ? -abs(n + 1) : -(abs(n) + 1); }
评论
f(n) { return -1 * abs(n) }
如何处理溢出问题?还是我错过了重点?
评论
你没有说他们期待什么样的语言......这是一个静态解决方案(Haskell)。它基本上弄乱了 2 个最重要的位:
f :: Int -> Int
f x | (testBit x 30 /= testBit x 31) = negate $ complementBit x 30
| otherwise = complementBit x 30
在动态语言(Python)中要容易得多。只需检查参数是否为数字 X 并返回返回 -X 的 lambda:
def f(x):
if isinstance(x,int):
return (lambda: -x)
else:
return x()
评论
class C a b | a->b where { f :: a->b }
instance C Int (()->Int) where { f=const.negate }
instance C (()->Int) Int where { f=($()) }
对于 JavaScript(或其他动态类型语言),您可以让函数接受 int 或 object 并返回另一个。即
function f(n) {
if (n.passed) {
return -n.val;
} else {
return {val:n, passed:1};
}
}
给
js> f(f(10))
-10
js> f(f(-10))
10
或者,您可以在强类型语言中使用重载,尽管这可能会违反规则,即
int f(long n) {
return n;
}
long f(int n) {
return -n;
}
评论
对于所有 32 位值(请注意,-0 为 -2147483648)
int rotate(int x)
{
static const int split = INT_MAX / 2 + 1;
static const int negativeSplit = INT_MIN / 2 + 1;
if (x == INT_MAX)
return INT_MIN;
if (x == INT_MIN)
return x + 1;
if (x >= split)
return x + 1 - INT_MIN;
if (x >= 0)
return INT_MAX - x;
if (x >= negativeSplit)
return INT_MIN - x + 1;
return split -(negativeSplit - x);
}
基本上需要将每个 -x => x => -x 循环与 y => -y => y 循环配对。所以我配对了 .split
例如,对于 4 位整数:
0 => 7 => -8 => -7 => 0
1 => 6 => -1 => -6 => 1
2 => 5 => -2 => -5 => 2
3 => 4 => -3 => -4 => 3
如前所述的问题并不要求函数必须只接受 32 位整数,只要求给定的 n 是 32 位整数。
红宝石:
def f( n )
return 0 unless n != 0
( n == n.to_i ) ? 1.0 / n : -(n**-1).to_i
end
这将在非常广泛的数字范围内起作用:
static int f(int n)
{
int lastBit = int.MaxValue;
lastBit++;
int secondLastBit = lastBit >> 1;
int tuple = lastBit | secondLastBit;
if ((n & tuple) == tuple)
return n + lastBit;
if ((n & tuple) == 0)
return n + lastBit;
return -(n + lastBit);
}
我最初的方法是使用最后一个位作为检查位,以了解我们在第一次或第二次调用中的位置。基本上,我会在第一次调用后将此位置于 1,以表示第一次调用已经通过的第二个调用。但是,这种方法被负数打败了,负数的最后一位在第一次调用时已经到达 1。
同样的理论也适用于大多数负数的倒数第二位。但是,通常发生的事情是,大多数时候,最后一位和倒数第二位是相同的。它们要么是负数的 1,要么是正数的 0。
因此,我的最后一个方法是检查它们是 1 还是都是 0,这意味着在大多数情况下,这是第一个调用。如果最后一位与倒数第二位不同,那么我假设我们在第二次调用时,只需重新反转最后一位。显然,这不适用于使用最后两位的非常大的数字。但是,再一次,它适用于非常广泛的数字。
C# 范围为 2^32 - 1 个数字,除 (Int32.MinValue) 之外的所有 int32 数字
Func<int, int> f = n =>
n < 0
? (n & (1 << 30)) == (1 << 30) ? (n ^ (1 << 30)) : - (n | (1 << 30))
: (n & (1 << 30)) == (1 << 30) ? -(n ^ (1 << 30)) : (n | (1 << 30));
Console.WriteLine(f(f(Int32.MinValue + 1))); // -2147483648 + 1
for (int i = -3; i <= 3 ; i++)
Console.WriteLine(f(f(i)));
Console.WriteLine(f(f(Int32.MaxValue))); // 2147483647
指纹:
2147483647
3
2
1
0
-1
-2
-3
-2147483647
评论
:D
boolean inner = true;
int f(int input) {
if(inner) {
inner = false;
return input;
} else {
inner = true;
return -input;
}
}
评论
从本质上讲,该函数必须将可用范围划分为大小为 4 的周期,其中 -n 位于 n 周期的另一端。但是,0 必须是大小为 1 的循环的一部分,否则 .由于 0 是单独的,因此我们的范围内必须有 3 个其他值(其大小是 4 的倍数)不在具有 4 个元素的适当循环中。0->x->0->x != -x
我选择了这些额外的奇怪值 , , 和 。此外,将正确映射到,但卡在那里而不是映射回来。我认为这是最好的折衷方案,因为它具有只有极值无法正常工作的良好属性。此外,这意味着它适用于所有 BigInt。MIN_INT
MAX_INT
MIN_INT+1
MIN_INT+1
MAX_INT
int f(int n):
if n == 0 or n == MIN_INT or n == MAX_INT: return n
return ((Math.abs(n) mod 2) * 2 - 1) * n + Math.sign(n)
Scala 中一个奇怪的、只有一点点聪明的解决方案,使用隐式转换:
sealed trait IntWrapper {
val n: Int
}
case class First(n: Int) extends IntWrapper
case class Second(n: Int) extends IntWrapper
case class Last(n: Int) extends IntWrapper
implicit def int2wrapper(n: Int) = First(n)
implicit def wrapper2int(w: IntWrapper) = w.n
def f(n: IntWrapper) = n match {
case First(x) => Second(x)
case Second(x) => Last(-x)
}
不过,我不认为这是完全正确的想法。
评论
Last(-8)
隐式可转换为 ,这就是使解决方案起作用的原因。-8
在PHP中
function f($n) {
if(is_int($n)) {
return (string)$n;
}
else {
return (int)$n * (-1);
}
}
我相信你能理解这种方法对其他语言的精神。我显式地转换回 int,以便让不使用弱类型语言的人更清楚。对于某些语言,您必须重载该函数。
这个解决方案的巧妙之处在于,无论你从字符串还是整数开始,它都能正常工作,并且在返回 f(n) 时不会明显改变任何内容。
在我看来,面试官是在问,“这个候选人是否知道如何标记数据以供以后操作”,以及“这个候选人是否知道如何标记数据,同时至少更改数据?您可以使用双精度、字符串或任何其他您想要强制转换的数据类型来执行此操作。
评论
似乎很容易。
<script type="text/javascript">
function f(n){
if (typeof n === "string") {
return parseInt(n, 10)
}
return (-n).toString(10);
}
alert(f(f(1)));
</script>
评论
C++ 版本,可能稍微扭曲了规则,但适用于所有数值类型(浮点数、整数、双精度值),甚至是重载一元减号的类类型:
template <class T>
struct f_result
{
T value;
};
template <class T>
f_result <T> f (T n)
{
f_result <T> result = {n};
return result;
}
template <class T>
T f (f_result <T> n)
{
return -n.value;
}
void main (void)
{
int n = 45;
cout << "f(f(" << n << ")) = " << f(f(n)) << endl;
float p = 3.14f;
cout << "f(f(" << p << ")) = " << f(f(p)) << endl;
}
评论
或者,您可以滥用预处理器:
#define f(n) (f##n)
#define ff(n) -n
int main()
{
int n = -42;
cout << "f(f(" << n << ")) = " << f(f(n)) << endl;
}
评论
使用全局...但事实呢?
bool done = false
f(int n)
{
int out = n;
if(!done)
{
out = n * -1;
done = true;
}
return out;
}
评论
怎么样
int f(int n)
{
return -abs(n);
}
评论
return x ^ ((x%2) ? 1 : -INT_MAX);
使用复数,可以有效地将否定数字的任务分为两个步骤:
- 将 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。
评论
float
int
感谢 C++ 中的重载:
double f(int var)
{
return double(var);
}
int f(double var)
{
return -int(var);
}
int main(){
int n(42);
std::cout<<f(f(n));
}
评论
我实际上并不是要为问题本身提供解决方案,但确实有几点评论,因为问题指出这个问题是(工作?)面试的一部分:
- 我首先会问:“为什么需要这样的功能?这是其中更大的问题是什么?“而不是试图当场解决实际提出的问题。这显示了我的想法以及我如何处理这样的问题。谁知道呢?这甚至可能是最初在面试中被问到这个问题的真正原因。如果答案是“没关系,假设它是需要的,并告诉我你将如何设计这个功能。然后我会继续这样做。
- 然后,我将编写我将使用的 C# 测试用例代码(显而易见的:循环从 到 ,对于该范围内的每个调用并检查结果是 ),告诉我将使用测试驱动开发来获得这样的函数。
int.MinValue
int.MaxValue
n
f(f(n))
-n
- 只有当面试官继续要求我解决提出的问题时,我才会真正开始尝试在面试过程中潦草地编写伪代码,以试图得到某种答案。但是,如果面试官能表明公司是什么样的,我真的不认为我会跳出来接受这份工作......
哦,这个答案假设面试是针对 C# 编程相关职位的。如果面试是与数学相关的职位,那当然是一个愚蠢的答案。;-)
评论
也许是作弊?(蟒蛇)
def f(n):
if isinstance(n, list):
return -n[0]
else:
return [n,0]
n = 4
print f(f(n))
--output--
-4
容易:
function f($n) {
if ($n%2 == 0) return ($n+1)*-1;
else return ($n-1);
}
评论
Clojure 解决方案:
(defmacro f [n] (if (list? n) `(- ~n) n))
也适用于任何大小、双精度和比率的正整数和负整数!
没有人说它必须是无国籍的。
int32 f(int32 x) {
static bool idempotent = false;
if (!idempotent) {
idempotent = true;
return -x;
} else {
return x;
}
}
作弊,但不像很多例子那么多。更邪恶的是偷看堆栈以查看您的呼叫者的地址是否为 &f,但这将更具可移植性(尽管不是线程安全的......线程安全版本将使用 TLS)。更邪恶:
int32 f (int32 x) {
static int32 answer = -x;
return answer;
}
当然,对于MIN_INT32的情况来说,这两种方法都不太有效,但是除非允许返回更广泛的类型,否则您对此无能为力。
评论
在 C 语言中,
int
f(int n) {
static int r = 0;
if (r == 1) {r--; return -1 * n; };
r++;
return n;
}
知道这是针对什么语言会有所帮助。 我错过了什么吗?许多“解决方案”似乎过于复杂,坦率地说,并非如此 工作(当我读到问题时)。
评论
我认为尽可能大的范围暗示了模块化算术解决方案。在一些模基 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)
这是 rossfabricant 答案的 C 实现。请注意,由于我一直坚持使用 32 位整数,因此 f( f( 2147483647 ) ) == 2147483647,而不是 -2147483647。
int32_t f( int32_t n )
{
if( n == 0 ) return 0;
switch( n & 0x80000001 ) {
case 0x00000000:
return -1 * ( n - 1 );
case 0x00000001:
return n + 1;
case 0x80000000:
return -1 * ( n + 1 );
default:
return n - 1;
}
}
如果将问题定义为允许 f() 接受并返回int64_t,则涵盖2147483647。当然,switch 语句中使用的文字必须更改。
评论
这个怎么样(C语言):
int f(int n)
{
static int t = 1;
return (t = t ? 0 : 1) ? -n : n;
}
刚刚尝试过,然后
f(f(1000))
返回 -1000
f(f(-1000))
返回 1000
这是正确的还是我错过了重点?
评论
实际上,这些问题更多的是关于看到面试官与规范、设计、错误处理、边界情况和解决方案的合适环境选择等搏斗,而不是关于实际解决方案。但是: :)
这里的函数是围绕封闭的 4 个周期的想法编写的。如果函数 f 只允许落在有符号的 32 位整数上,那么上面的各种解决方案都将起作用,除了其他人指出的三个输入范围数字。minint 永远不会满足函数式,因此如果这是输入,我们将引发异常。
在这里,我允许我的 Python 函数操作并返回元组或整数。任务规范承认这一点,它只指定函数的两个应用程序应该返回一个对象,如果它是 int32,则该对象等于原始对象。(我会询问有关规范的更多细节。
这使得我的轨道很好且对称,并覆盖了所有输入整数(最小值除外)。我最初设想循环访问半整数值,但我不想纠结于舍入错误。因此,元组表示形式。这是一种将复杂旋转作为元组潜入的方法,而无需使用复杂的算术机制。
请注意,在调用之间不需要保留任何状态,但调用方确实需要允许返回值为元组或整数。
def f(x) :
if isinstance(x, tuple) :
# return a number.
if x[0] != 0 :
raise ValueError # make sure the tuple is well formed.
else :
return ( -x[1] )
elif isinstance(x, int ) :
if x == int(-2**31 ):
# This value won't satisfy the functional relation in
# signed 2s complement 32 bit integers.
raise ValueError
else :
# send this integer to a tuple (representing ix)
return( (0,x) )
else :
# not an int or a tuple
raise TypeError
因此,将 f 应用于 37 两次得到 -37,反之亦然:
>>> x = 37
>>> x = f(x)
>>> x
(0, 37)
>>> x = f(x)
>>> x
-37
>>> x = f(x)
>>> x
(0, -37)
>>> x = f(x)
>>> x
37
将 f 应用于零两次得到零:
>>> x=0
>>> x = f(x)
>>> x
(0, 0)
>>> x = f(x)
>>> x
0
我们处理一个问题没有解决方案的情况(在 int32 中):
>>> x = int( -2**31 )
>>> x = f(x)
Traceback (most recent call last):
File "<pyshell#110>", line 1, in <module>
x = f(x)
File "<pyshell#33>", line 13, in f
raise ValueError
ValueError
如果您认为该函数通过模仿乘以 i 的 90 度旋转来打破“无复杂算术”规则,我们可以通过扭曲旋转来改变它。这里的元组表示半整数,而不是复数。如果在数轴上跟踪轨道,则将得到满足给定函数关系的不相交环。
f2: n -> (2 abs(n) +1, 2 sign( n) ) if n is int32, and not minint.
f2: (x, y) -> sign(y) * (x-1) /2 (provided y is \pm 2 and x is not more than 2maxint+1
练习:通过修改 f 来实现此 f2。还有其他解决方案,例如,让中间着陆点是除半整数之外的有理数。有一个分数模块可能会被证明是有用的。您需要一个符号函数。
这个练习真的让我领悟到了动态类型语言的乐趣。我在 C 中看不到这样的解决方案。
作为一个数学家,我想分享我对这个有趣问题的看法。我认为我有最有效的解决方案。
如果我没记错的话,你只需翻转第一位就否定了一个有符号的 32 位整数。例如,如果 n = 1001 1101 1110 1011 1110 0000 1110 1010,则 -n = 0001 1101 1110 1011 1110 0000 1110 1010。
那么我们如何定义一个函数 f,它接受一个有符号的 32 位整数并返回另一个有符号的 32 位整数,其属性是取 f 两次与翻转第一位相同?
让我重新表述这个问题,而不提及整数等算术概念。
我们如何定义一个函数 f,它接受长度为 32 的 0 和 1 序列并返回相同长度的 0 和 1 序列,其属性是取 f 两次与翻转第一位相同?
观察:如果你能回答上面的32位大小写问题,那么你也可以回答64位大小写、100位大小写等。您只需将 f 应用于前 32 位。
现在,如果您能回答 2 位大小写的问题,瞧!
是的,事实证明,更改前 2 位就足够了。
这是伪代码
1. take n, which is a signed 32-bit integer.
2. swap the first bit and the second bit.
3. flip the first bit.
4. return the result.
备注:步骤 2 和步骤 3 可以一起称为 (a,b) --> (-b, a)。看起来很眼熟?这应该会提醒您平面旋转 90 度和乘以 -1 的平方根。
如果我只是在没有冗长的前奏的情况下单独展示伪代码,那看起来就像一只兔子,我想解释一下我是如何得到解决方案的。
评论
int f(int x){
if (x < 0)
return x;
return ~x+1; //two's complement
}
评论
这个是用 Python 编写的。适用于 n 的所有负值:
f = abs
评论
这是我从未见过人们使用的变体。由于这是 ruby,所以 32 位整数的东西有点消失了(当然可以添加检查)。
def f(n)
case n
when Integer
proc { n * -1 }
when Proc
n.call
else
raise "Invalid input #{n.class} #{n.inspect}"
end
end
(-10..10).each { |num|
puts "#{num}: #{f(f(num))}"
}
这里有一个证明,为什么这样的函数不能存在,对于所有数字,如果它不使用额外的信息(除了 32 位的 int):
我们必须有 f(0) = 0。(证明:假设 f(0) = x。则 f(x) = f(f(0)) = -0 = 0。现在,-x = f(f(x)) = f(0) = x,这意味着 x = 0。
此外,对于任何 和 ,假设 .我们想要那时。和。总而言之:如果 、 那么 、 和 和 。x
y
f(x) = y
f(y) = -x
f(f(y)) = -y => f(-x) = -y
f(x) = y
f(-x) = -y
f(y) = -x
f(-y) = x
因此,我们需要将除 0 以外的所有整数除成 4 个集合,但我们有奇数个这样的整数;不仅如此,如果我们去掉没有正对应物的整数,我们仍然有 2(mod4) 个数字。
如果我们去掉剩下的 2 个最大数字(按 abs 值),我们可以得到函数:
int sign(int n)
{
if(n>0)
return 1;
else
return -1;
}
int f(int n)
{
if(n==0) return 0;
switch(abs(n)%2)
{
case 1:
return sign(n)*(abs(n)+1);
case 0:
return -sign(n)*(abs(n)-1);
}
}
当然,另一种选择是不遵守 0,并获得我们删除的 2 个数字作为奖励。(但这只是一个愚蠢的假设。
评论
n = -2147483648
abs(n)
创建许多解决方案的一种方法是注意,如果我们将整数分为两个集合 S 和 R s.t -S=S,-R=R,以及一个函数 g s.t g(R) = S
然后我们可以按如下方式创建 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。
很简单,只需返回看起来等于任何整数的东西,并且可以从整数转换。f
public class Agreeable
{
public static bool operator==(Agreeable c, int n)
{ return true; }
public static bool operator!=(Agreeable c, int n)
{ return false; }
public static implicit operator Agreeable(int n)
{ return new Agreeable(); }
}
class Program
{
public static Agreeable f(Agreeable c)
{ return c; }
static void Main(string[] args)
{
Debug.Assert(f(f(0)) == 0);
Debug.Assert(f(f(5)) == -5);
Debug.Assert(f(f(-5)) == 5);
Debug.Assert(f(f(int.MaxValue)) == -int.MaxValue);
}
}
该问题指出“32 位有符号整数”,但没有指定它们是二进制补码还是一补码。
如果您使用 1-complement,则所有 2^32 值都出现在长度为 4 的循环中 - 您不需要 0 的特殊情况,也不需要条件。
在 C 语言中:
int32_t f(int32_t x)
{
return (((x & 0xFFFFU) << 16) | ((x & 0xFFFF0000U) >> 16)) ^ 0xFFFFU;
}
这工作原理是
- 交换高低 16 位块
- 反转其中一个块
经过两次传递后,我们得到原始值的按位倒数。在一补表示中,这等同于否定。
例子:
Pass | x
-----+-------------------
0 | 00000001 (+1)
1 | 0001FFFF (+131071)
2 | FFFFFFFE (-1)
3 | FFFE0000 (-131071)
4 | 00000001 (+1)
Pass | x
-----+-------------------
0 | 00000000 (+0)
1 | 0000FFFF (+65535)
2 | FFFFFFFF (-0)
3 | FFFF0000 (-65535)
4 | 00000000 (+0)
评论
const unsigned long Magic = 0x8000000;
unsigned long f(unsigned long n)
{
if(n > Magic )
{
return Magic - n;
}
return n + Magic;
}
0~2^31
评论
int j = 0;
void int f(int n)
{
j++;
if(j==2)
{
j = 0;
return -n;
}
return n;
}
:D
以下情况如何:
int f (int n)
{
static bool pass = false;
pass = !pass;
return pass? n : -n;
}
评论
int f( int n ){
return n==0?0:(n&1?n:-n)+(n<0?-1:1);
}
评论
我的给出了正确的答案......50%的时间,一直如此。
int f (int num) {
if (rand () / (double) RAND_MAX > 0.5)
return ~num + 1;
return num;
}
评论
这适用于 -1073741823 到 1073741822 的范围:
int F(int n)
{
if(n < 0)
{
if(n > -1073741824)
n = -1073741824 + n;
else n = -(n + 1073741824);
}
else
{
if(n < 1073741823)
n = 1073741823 + n;
else n = -(n - 1073741823);
}
return n;
}
它的工作原理是将 32 位有符号 int 的可用范围一分为二。该函数的第一次迭代将 n 单独置于该范围之外。第二次迭代检查它是否超出此范围 - 如果是,则将其放回该范围内,但将其设为负数。
它实际上是一种保留有关值 n 的额外“位”信息的方法。
评论
我会你改变 2 个最重要的位。
00.... => 01.... => 10.....
01.... => 10.... => 11.....
10.... => 11.... => 00.....
11.... => 00.... => 01.....
正如你所看到的,它只是一个补充,省略了携带的部分。
我是怎么得到答案的?我的第一个想法只是对对称性的需要。4 圈回到我开始的地方。起初我以为,那是 2 位格雷码。然后我认为实际上标准的二进制就足够了。
评论
PHP,不使用全局变量:
function f($num) {
static $mem;
$answer = $num-$mem;
if ($mem == 0) {
$mem = $num*2;
} else {
$mem = 0;
}
return $answer;
}
适用于整数、浮点数和数字字符串!
刚刚意识到这做了一些不必要的工作,但是,无论如何
void f(int x)
{
Console.WriteLine(string.Format("f(f({0})) == -{0}",x));
}
对不起,伙计们...这太诱人了;)
C++解决方案;
long long f(int n){return static_cast <long long> (n);}
int f(long long n){return -static_cast <int> (n);}
int n = 777;
assert(f(f(n)) == -n);
另一个作弊解决方案。我们使用一种允许运算符重载的语言。然后我们让 f(x) 返回一些重载的东西,以始终返回 true。这似乎与问题描述相符,但显然违背了谜题的精神。==
Ruby 示例:
class Cheat
def ==(n)
true
end
end
def f(n)
Cheat.new
end
这给了我们:
>> f(f(1)) == -1
=> true
但也(不太令人惊讶)
>> f(f(1)) == "hello world"
=> true
int f(const int n) {
static int last_n;
if (n == 0)
return 0;
else if (n == last_n)
return -n;
else
{
last_n = n;
return n;
}
}
骇人听闻,但正确。
记住你上一个状态不是一个足够好的答案吗?
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))
}
评论
有些是相似的,但只是想写下我的第一个想法(用 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)) 实际调用两个不同的函数
JavaScript 单行代码:
function f(n) { return ((f.f = !f.f) * 2 - 1) * n; }
评论
我还没有看过其他答案,我认为按位技术已经被彻底讨论过了。
我以为我会在 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(); }
评论
f(f(x)) == -x
cout << x << (f(f(x)) == -x ? " works." : " doesn't work.") << endl;
int f(int n)
{
static long counter=0;
counter++;
if(counter%2==0)
return -n;
else
return n;
}
另一种方法是将状态保持在一位,并在负数的情况下注意二进制表示来翻转它...... 限制为 2^29
int ffn(整数 n) {
n = n ^ (1 << 30); //flip the bit
if (n>0)// if negative then there's a two's complement
{
if (n & (1<<30))
{
return n;
}
else
{
return -n;
}
}
else
{
if (n & (1<<30))
{
return -n;
}
else
{
return n;
}
}
}
x86 asm(AT&T 风格):
; input %edi
; output %eax
; clobbered regs: %ecx, %edx
f:
testl %edi, %edi
je .zero
movl %edi, %eax
movl $1, %ecx
movl %edi, %edx
andl $1, %eax
addl %eax, %eax
subl %eax, %ecx
xorl %eax, %eax
testl %edi, %edi
setg %al
shrl $31, %edx
subl %edx, %eax
imull %ecx, %eax
subl %eax, %edi
movl %edi, %eax
imull %ecx, %eax
.zero:
xorl %eax, %eax
ret
已检查代码,传递了所有可能的 32 位整数,错误为 -2147483647(下溢)。
这个怎么样?
int nasty(int input)
{
return input + INT_MAX/2;
}
评论
number f( number n)
{
static count(0);
if(count > 0) return -n;
return n;
}
f(n) = n
f(f(n)) = f(n) = -n
评论
count++
int f(int n) {
return ((n>0)? -1 : 1) * abs(n);
}
评论
这个 Perl 解决方案适用于整数、浮点数和字符串。
sub f {
my $n = shift;
return ref($n) ? -$$n : \$n;
}
尝试一些测试数据。
print $_, ' ', f(f($_)), "\n" for -2, 0, 1, 1.1, -3.3, 'foo' '-bar';
输出:
-2 2
0 0
1 -1
1.1 -1.1
-3.3 3.3
foo -foo
-bar +bar
评论
n
从来没有人说过f(x)必须是同一类型。
def f(x):
if type(x) == list:
return -x[0]
return [x]
f(2) => [2]
f(f(2)) => -2
虽然问题说 n 必须是 32 位的 int,但它并没有说参数或返回类型必须是 32 位的 int。这应该在 java 中编译——在 c 中,你可以去掉 != 0
private final long MAGIC_BIT=1<<38;
long f(long n) {
return n & MAGIC_BIT != 0 ? -(n & !MAGIC_BIT) : n | MAGIC_BIT;
}
编辑:
这实际上是一个非常好的面试问题。最好的问题是那些难以或不可能回答的问题,因为它迫使人们仔细思考,你可以观察和寻找:
- 他们只是放弃了吗?
- 他们说这很愚蠢吗?
- 他们是否尝试独特的方法?
- 他们在解决问题时是否与您沟通?
- 他们是否要求进一步完善要求?
等。
永远不要只回答行为问题,除非你有一个很好的答案。始终保持愉快,并尝试让提问者参与进来。不要沮丧,不要过早放弃!如果你真的一无所获,尝试一些完全非法的可能工作,你会得到几乎全部的信用。
这个怎么样:
do
local function makeFunc()
local var
return function(x)
if x == true then
return -var
else
var = x
return true
end
end
end
f = makeFunc()
end
print(f(f(20000)))
这是一个受复数不能用于解决此问题的要求或声明启发的解决方案。
乘以 -1 的平方根是一个想法,它似乎只是失败了,因为 -1 在整数上没有平方根。但是,使用像 mathematica 这样的程序可以给出等式
(18494364652+1) mod (232-3) = 0.
这几乎与平方根 -1 一样好。函数的结果必须是有符号整数。因此,我将使用修改后的模运算 mods(x,n),该运算返回整数 y 与最接近 0 的 x 模 n 一致。只有极少数编程语言具有 suc 模运算,但它可以很容易地定义。例如,在 python 中它是:
def mods(x, n):
y = x % n
if y > n/2: y-= n
return y
使用上面的等式,问题现在可以解决为
def f(x):
return mods(x*1849436465, 2**32-3)
这满足 31 31
范围内的所有整数。的结果也在这个范围内,但计算当然需要 64 位整数。
f(f(x)) = -x
[-2
-2, 2
-2]
f(x)
f(n) { return IsWholeNumber(n)? 1/n : -1/n }
评论
C++
struct Value
{
int value;
Value(int v) : value(v) {}
operator int () { return -value; }
};
Value f(Value input)
{
return input;
}
与函数重载解决方案类似,在 python 中:
def f(number):
if type(number) != type([]):
return [].append(number)
else:
return -1*number[0]
另类:static datamembers
蟒蛇 2.6:
f = lambda n: (n % 2 * n or -n) + (n > 0) - (n < 0)
我意识到这对讨论没有任何帮助,但我无法抗拒。
我还有另一个解决方案,可以在一半的时间内工作:
def f(x):
if random.randrange(0, 2):
return -x
return x
这也是一个解决方案(但我们正在稍微改变规则):
def f(n):
if isinstance(n,int):
return str(n)
else:
return -int(n)
int f(int n) { static int x = 0; result = -x; x = n; return result; }
这是一个带否定的单条目 FIFO。当然,它不适用于最大负数。
评论
在 Python 中
f=lambda n:n[0]if type(n)is list else[-n]
我相信这符合所有要求。没有说参数必须是 32 位有符号整数,只是说您传入的值“n”是。
long long f(long long n)
{
int high_int = n >> 32;
int low_int = n & 0xFFFFFFFF;
if (high_int == 0) {
return 0x100000000LL + low_int;
} else {
return -low_int;
}
}
好问题!
我花了大约 35 秒的时间来思考和写作:
int f(int n){
static int originalN=0;
if (n!=0)
originalN=n;
return n-originalN;
}
评论
n
f(f(n))
斯卡拉:
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();
}
C# 重载:
string f(int i) {
return i.ToString();
}
int f(string s) {
return Int32.Parse(s) * -1;
}
或
object f(object o) {
if (o.ToString.StartsWith("s"))
return Int32.Parse(s.Substring(1)) * -1;
return "s" + i.ToString();
}
另一个利用短路的 Javascript 解决方案。
function f(n) {return n.inv || {inv:-n}}
f(f(1)) => -1
f(f(-1)) => 1
Tcl:
proc f {input} {
if { [string is integer $input] } {
return [list expr [list 0 - $input]]
} else {
return [eval $input]
}
}
% f [f 1]
-1
按照其他一些答案的思路......如果是整数,则返回一个返回该数字负数的命令。如果它不是数字,请计算它并返回结果。
少于 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*
这是一个 C/C++ 解决方案,它不使用任何按位运算符,也不需要任何数学库,尽管它有点作弊......
double f(double n)
{
if (n == (double)(int)n)
return n + 0.5;
else
return -(n - 0.5);
}
这适用于所有 32 位整数,但只有一个例外(因为它的反面不能存储在 32 位整数系统中)。 将始终是,除非在那种情况下。0x80000000
f(f(n)) == -n
true
不过,我相信有一种更简单、更快速的实现方法。这只是我想到的第一件事。
我以为我会在不先看其他人的答案的情况下尝试这个:
#include <stdio.h> #include <limits.h> #include <stdlib.h> int f(int n) { if(n > 0) { if(n % 2) return -(++n); else { return (--n); } } else { if(n % 2) return -(--n); else { return (++n); } } } int main(int argc, char* argv[]) { int n; for(n = INT_MIN; n < INT_MAX; n++) { int N = f(f(n)); if(N != -n) { fprintf(stderr, "FAIL! %i != %i\n", N, -n); } } n = INT_MAX; int N = f(f(n)); if(N != -n) { fprintf(stderr, "FAIL! n = %i\n", n); } return 0; }
输出:[nothing]
Lua:
function f(n)
if type(n) == "number" then
return (-number) .. ""
else
return number + 0
end
end
利用 JavaScript 异常。
function f(n) {
try {
return n();
}
catch(e) {
return function() { return -n; };
}
}
f(f(0)) => 0
f(f(1)) => -1
评论
除 int 外有效。MaxValue 和 int。最小值
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));
}
评论
0
0
-2147483648
-2147483648
x => -x
2147483647
-2147483647
int func(int a)
{
static int p = 0;
int ret = a;
if ( p ) ret *= -1;
p ^= 1;
return ret;
}
我认为这类问题的答案最好通过使用图表直观地解释。当我们忽略零时,我们可以将整数分成 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;
}
}
评论
- 将 n 转换为符号和大小表示;
- 添加 1/4 的范围;
- 转换回来。
#define STYPE int
STYPE sign_bit = (unsigned STYPE) 1 << ( sizeof ( STYPE ) * 8 - 1 );
STYPE f ( STYPE f )
{
unsigned STYPE smf = f > 0 ? f : -f | sign_bit;
smf += sign_bit >> 1;
return smf & sign_bit ? -( smf & ~sign_bit ) : smf;
}
#include <cmath>
int f(int n)
{
static int count = 0;
return ::cos(M_PI * count++) * n;
}
评论
这很简单!
每个数字以 4 个周期映射到另一个数字,其中所需的条件成立。
例:
规则是:
0 → 0
±2³¹ → ±2³¹
奇数→偶数,偶数→ -奇数:
对于所有 K, 0 < K < 2³⁰: (2K-1) → (2K) → (-2K+1) → (-2K) → (2K-1)
唯一不匹配的值是 ±(2³¹-1),因为只有两个。必须有两个不能匹配,因为在二的补码系统中只有 4 的倍数,其中 0 和 ±2³¹ 已经保留。
在 1 的补码系统中,存在 +0 和 -0。我们开始了:
对于所有 K, 0 < K < 2³⁰: (+2K) → (+2K+1) → (-2K) → (-2K-1) → (+2K)
这个想法已经在其他答案中使用过,但我把它写进了 Python 的一行中:
def f(n):
return str(n) if type(n) == int else -int(n)
A C 函数:
int f(int n) /* Treats numbers in the range 0XC0000000 to 0X3FFFFFFF as valid to
generate f(f(x)) equal to -x. If n is within this range, it will
project n outside the range. If n is outside the range, it will
return the opposite of the number whose image is n. */
{
return n ? n > 0 ? n <= 0X3FFFFFFF ? 0X3FFFFFFF + n : 0X3FFFFFFF - n :\
n >= 0XC0000000 ? 0XC0000000 + n : 0XC0000000 - n : 0;
}
用于测试和下载的 Ideone 链接
好吧,我既不是数学家,也不是编程专家,但这不是很容易吗?
int f(int i) {
static bool b;
if (b) {
b = !b;
return i;
} else {
b = !b;
return -i;
}
}
用大大小小的正负值、INT_MIN、INT_MAX进行测试,它似乎有效......如果这是一个问题,可以使线程安全,但它不是任务的一部分。
或者也许我错过了什么?
评论
var x = f(1), y = f(2); console.log(f(x));
f(f(n)) == -n
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)
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)
用 coffeescript 打高尔夫球:
f = (n)-> -n[0] or [n]
评论
function f(n) { return -n[0] || [n] }
)
使用循环排列方法来执行此操作。
-b a b -a
一、乙、一、-乙
在微不足道的情况下 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 就可以了)
使用问题中给出的信息,您可以
- 从 2-补码转换为符号位表示
- 如果设置了最后一个位,则翻转符号位和最后一个位;否则,只翻转最后一点
- 转换回 2-补码。
所以你基本上是奇数 -> 偶数 -> 奇数或偶数 -> 奇数 -> 偶数,并且只更改偶数的符号。唯一不起作用的数字是 -2^31
法典:
function f(x) {
var neg = x < 0;
x = Math.abs(x) ^ 1;
if (x & 1) {
neg = !neg;
}
return neg ? -x : x;
}
也许我错过了什么?
这难道不是这么简单吗?
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;}
丑陋但有效。
评论
它通过保存状态来作弊,但它有效,将操作一分为二:-n = (~n + 1) 表示整数
int f(int n) {
static int a = 1;
a = !a;
if (a) {
return (~n);
} else {
return (n+1);
}
}
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
评论
x
x.length == 1
简单的 Python 解决方案之所以成为可能,是因为对 f(x) 应该输出的内容没有限制,只有 f(f(x)):
def f(x):
return (isinstance(x, tuple) and -x[0]) or (x,)
评论
(x)
返回。我想你的意思是x
(x,)
我承认我会作弊,但仍然符合要求。这是编程魔法,而不是真正的数学。它适用于整个范围,除了 -2^31。
int f(int n)
{
static bool eFlag = false; // Only executed once
eFlag = !eFlag;
return eFlag?-n:n;
}
C++ 中的另一个作弊解决方案,运算符重载。
struct func {
int n;
func operator()(int k) { n = -k; return *this; }
int operator()(const func &inst) { return inst.n; }
} f;
下面是一个简短的 Python 答案:
def f(n):
m = -n if n % 2 == 0 else n
return m + sign(n)
一般案例
对上述内容稍作调整可以处理我们希望自调用否定输入的情况——例如,如果 ,这意味着:k
k = 3
g(g(g(n))) = -n
def g(n):
if n % k: return n + sign(n)
return -n + (k - 1) * sign(n)
其工作原理是将 0 保留在原位并创建长度为 2 * k 的循环,因此,在任何循环中,n 和 -n 的距离为 k。具体来说,每个周期如下所示:
N * k + 1, N * k + 2, ... , N * k + (k - 1), - N * k - 1, ... , - N * k - (k - 1)
或者,为了更容易理解,以下是以下示例循环:k = 3
1, 2, 3, -1, -2, -3
4, 5, 6, -4, -5, -6
这组循环最大化了在以零为中心的任何机器类型(例如有符号 int32 或有符号 int64 类型)中工作的输入范围。
兼容范围分析
映射实际上必须形成长度的循环,其中是一个特例 1-长度循环,因为 -0 = 0。因此,当且仅当输入的范围 - 1(补偿 0)是 2 * k 的倍数,并且正负范围相反时,一般问题是可解的。x -> f(x)
2 * k
x = 0
k
对于有符号整数表示,我们总是有一个最小的负数,在范围内没有正对应数,因此问题在整个范围内变得无法解决。例如,a 的范围为 [-128, 127],因此不可能在给定范围内。signed char
f(f(-128)) = 128
Objective-C语言
这适用于除“-1”以外的所有数字。
如果您要从使用到使用,那么您可以将 -1 值设置为,然后第二次将它们转换为 +1,但我觉得这欺骗了提问者的意图。int
NSInt
NULL
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;
}
当然,这一切都可以缩短为一行,但其他人可能无法继续阅读......
无论如何,我将布尔逻辑存储在数字为奇数或偶数的状态下。
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 < n < System.Int32.MaxValue
我试着用罗德里克·查普曼(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%。(正数和负数的随机数据集,足够的重复,并防止编译器优化代码,并进行预热。这并不奇怪,因为该函数被调用了两次,因此无分支版本中的操作数量和可能的良好分支预测: .当我更改基准以测量时: ,分支版本仅快 28%。我认为这证明了分支预测在第一种情况下实际上起到了一定的作用。更多证明:当测试时,事实证明分支版本快了 42%。f(f(i))
f(i)
f(f(f(f(i))))
Wolfram 语言中的解决方案:
f[f[n_]] := -n
应用:
In[2]:= f[f[10]]
Out[2]= -10
In[3]:= f[10]
Out[3]= f[10]
因为问题没有说明f(n)的值,所以f[n]仍然未计算。
Javascript的
function f(n) {
return typeof n === "number" ?
function() {return -n} :
n();
}
根据Microsoft/Google的面试官在面试中通常会问的问题,我相信提问者是指一种创新的、轻量级的、简单的解决方案,它将使用按位运算,而不是那些复杂的高级答案。
受到@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 中,将 1 加到 x,然后再次将其替换为 n 的最左边两位。
如果我们继续运行 f(n) 并使用另一个 f(n) 作为参数 n,则最左边的两个位将像这样旋转:
00 --> 01 --> 10 --> 11 --> 00 ...
请注意,最右边的 30 位不会改变。8 位整数的示例:
示例 1:
- > f(00001111) = 01001111
- > f(01001111) = 10001111 [这是原始值的负数,00001111]
示例 2:
- > f(11101010) = 00101010
- > f(00101010) = 01101010 [这是原始值的负数,11101010]
在 中,由于几乎没有任何信息被传递下来,因此必须求助于允许状态信息作为函数返回的一部分传递的方法,而不会危及传递内容的可用性:awk
jot - -5 5 | mawk 'function _(__,___) {
return (__~(___=" ")) \
\
? substr("",sub("^[ ]?[+- ]*",\
substr(" -",__~__,index("_"___,___)-\
(__~"[-]")),__))\
(__~"[-]"?"":___)__\
: (+__<-__?___:(___)___)__
} BEGIN { CONVFMT=OFMT="%.17g"
} {
print "orig", +(__=$(__<__))<-__?__:" "__,
"f(n)....", _(__),_(_(__)),_(_(_(__))),
_(_(_(_(__)))), _(_(_(_(_(__)))))
}' |gcat -n | lgp3 5
1 orig -5 f(n).... -5 5 -5 5 -5
2 orig -4 f(n).... -4 4 -4 4 -4
3 orig -3 f(n).... -3 3 -3 3 -3
4 orig -2 f(n).... -2 2 -2 2 -2
5 orig -1 f(n).... -1 1 -1 1 -1
6 orig 0 f(n).... 0 -0 0 -0 0
7 orig 1 f(n).... 1 -1 1 -1 1
8 orig 2 f(n).... 2 -2 2 -2 2
9 orig 3 f(n).... 3 -3 3 -3 3
10 orig 4 f(n).... 4 -4 4 -4 4
11 orig 5 f(n).... 5 -5 5 -5 5
因此,这样做的限制是只有已经采用字符串格式的整数或浮点值才能使用而不会有风险,因为额外的 ASCII 空格被作为状态信息预置\040
这种方法的好处是
它愿意为你提供“负零”,
对于小于绝对值的整数, 只需添加一个加号,
2^53
即
+f(f(_))
对函数调用本身将具有隐式 代表您完成的类型转换, 结果值将再次为数字
对于大整数,只需去掉任何前导空格
substr()
轻松处理 Bigintegers,而不会有丢失的风险 从类型铸造到双精度浮子的精度
`
1 orig -99999999999999999999999999999999
f(n)....
-99999999999999999999999999999999
99999999999999999999999999999999
-99999999999999999999999999999999
99999999999999999999999999999999
-99999999999999999999999999999999
2 orig -1239999999999999999999999999999
f(n).... -1239999999999999999999999999999
1239999999999999999999999999999
-1239999999999999999999999999999
1239999999999999999999999999999
-1239999999999999999999999999999`
我来晚了,现在可能是一个墓地。但我有 2 个贡献,灵感来自 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
评论