这是一个面试问题,我丝毫不知道如何解决。采访结束了,但是我真的很想看看他们在寻找什么。我试图对此进行混淆,以尊重提出要求的公司。
存在一个由S
位组成的秘密整数N
。我们的工作是高度确定地猜测这个秘密整数。
我们只能通过秘密方法S
访问foo(G)
,该秘密方法包含一个猜测G
和一个XOR,它们与S
和一个随机生成的值{{1 }},其中V
中的每一位都有1的10%几率。然后计算1的数量并将其返回为整数
V
每次调用foo(g):
generate v
return bin(g ^ v ^ s).count('1')
都会生成 V
假设我们在面试失败或世界爆炸之类的事情发生前,有100,000次尝试运行foo
的机会。
我们如何处理呢?
让我抓狂的是,即使猜对了正确答案,也有N / 10的机会从foo
返回非零值。因此,即使是蛮力尝试也似乎不在桌上。
答案 0 :(得分:0)
假设:如果您对具有相同G的函数foo(G)
重复足够的次数,则foo(G)
的平均结果将足够接近期望值。
例如,假设S
有N位,其中M位为1,设G = N bits of 0
,则foo(G)
的期望值为E(N,M)=M*0.9 + (N-M)*0.1
。既然我们知道N,并且我们可以得到foo(G)
的平均值,那么很容易确定M的数量。实际上,我们甚至不需要找出M。
当我们有数字E(N,M)
时,其余的将很简单:迭代i至N,并使G的第i位等于1,而其余的为零,然后重复foo(G)
足够多次。如果s
的第i位等于1,则foo(G)
的期望为E(N-1,M-1)+0.1=E(N,M)-0.8
,否则,如果S
的第i位等于0,则期望为foo(G)
中的E(N-1,M)+0.9=E(N,M)+0.8
。
然后您可以算出S
的值。在同一个G上重复foo(G)
的次数越多,确定性就越高。
一些示例代码:
import numpy as np
S = 1117506159690372465501725393907 # an 100 bit number
def foo(S, N, G):
bits = np.random.choice(2, size=N, p=[0.9,0.1])
V = int("".join(str(b) for b in bits), 2)
return bin(G^V^S).count('1')
if __name__ == '__main__':
N = 100
result = np.empty((101,1000))
for j in range(1000):
G = int("0" * N, 2)
result[0,j] = foo(S, N, G)
for i in range(100):
for j in range(1000):
G = int("0"*i + "1" + "0"*(N-i-1), 2)
result[i+1, j] = foo(S, N, G)
avg = np.mean(result, axis=1)
avg -= avg[0]
out = "0b"+"".join("1" if num < 0 else "0" for num in avg[1:])
print(str(bin(S))==out) # True
答案 1 :(得分:0)
这是我要怎么做:
from random import random as r
from collections import defaultdict
N = 8 # Number of bits
S = 123 # Secret number
stop_iter = 100 # Number of iterations
#stop_tol -- also an option, but seems risky given noise
def foo(g):
V = int(''.join([str(int(r() < 0.1)) for _ in range(N)]), 2)
return bin(g ^ V ^ S).count('1')
def test_guess(g, n=10):
total = 0
for _ in range(n):
total += foo(g)
return total / n
def test_perturb(g, p, n=10):
g ^= (1 << p)
return test_guess(g, n)
def test_bit_positions(g):
deltas = {}
for i in range(N):
deltas[i] = test_perturb(g, i)
return deltas
def itemval(i): return i[1]
history = defaultdict(list)
guess = 0 # Initial
for _ in range(stop_iter):
deltas = test_bit_positions(guess)
error = sum(deltas.values())
history[guess].append(error)
(index, delta) = min(deltas.items(), key=itemval)
guess ^= (1 << index)
print(guess, bin(guess), "after flipping bit %d" % index, error)
# If you had to, you could evaluate history at each iteration,
# trying to identify a value that has set itself apart
# potentially halting early but slowing the program
mean_error = {k:(sum(lst) / len(lst)) for (k,lst) in history.items()}
print()
print("Results:")
mean_error = sorted(mean_error.items(), key=itemval)
for (guess, err) in mean_error[:5]:
print(guess, err)
print()
print("Guess:", mean_error[0][0])
示例输出(N = 8,S = 123,stop_iter = 100,n = 10):
Results:
123 12.799021276595743
127 17.55975
59 17.564333333333334
251 17.583
121 17.58742857142857
Guess: 123 (Correct)
Calls to foo(): 8000
示例输出(N = 20,S = 12345,stop_iter = 100,n = 10)
Results:
12345 56.19999999999998
77881 69.69999999999999
12601 69.85
274489 69.93333333333334
8249 70.10000000000001
Guess: 12345 (Correct)
Calls to foo(): 20000
基本迭代优化,通过比较您当前猜想的N个扰动版本,尝试使error
项尽可能接近零。由于噪音,这将比平时更加棘手。
您还可以调整一些参数,两个n
函数中的test_
默认参数以及迭代次数stop_iter
。