给定一个由奇数和偶数组成的数组,我想获得XOR大于或等于4的(偶数)和(奇数)对的数量。我用下面的代码尝试了此方法,但是它以O(n ^ 2)(yikes)运行。请问有人可以建议一种优化方法吗?
n = int(raw_input()) #array size
ar = map(int, raw_input().split()) #the array
cnt = 0
for i in xrange(len(ar)):
for j in xrange(i+1, len(ar)):
if ar[i] ^ ar[j] >= 4 and (not ar[i] & 1 and not ar[j] & 1):
cnt += 1; #print ar[i],ar[j],ar[i]^ar[j];
elif ar[i] ^ ar[j] >= 4 and (ar[i] & 1 and ar[j] & 1):
cnt += 1
print cnt
编辑:我发现了一些东西。任何数字x,其在%4之后产生余数,即x%4!= 0,则在对其进行异或运算时将与数字-2本身求和为2。例如,6不能被4整除,因此6 XOR 6-2(4),==>2。10不能被4整除,因此10 XOR 10-2(8)==> 2。您能告诉我这如何帮助我优化代码吗?我现在才知道,我只需要寻找可被4整除的数字并找到+ 2的计数即可。
答案 0 :(得分:2)
为简单起见,我们假设该数组没有重复项。为了使2个数字之间的XOR> = 4,它们需要具有任何不同的位(不包括低2位)。既然我们已经知道它们是偶数或奇数对,则它们的最低位是相同的。
请注意,对于任何数字X,X XOR(X + 4 + k)始终为> =4。因此,问题是要考虑X XOR(X + 1),X XOR(X + 2)和X XOR(X + 3)。 当第三低位仅加1时,X XOR(X + 1)将> =4。这意味着,我们的X以011结尾,所以X + 1以100结尾,或者我们的X以111结尾,所以X + 1以000结尾。在两种情况下,这都意味着X%4 =3。在任何其他情况下(X%4!= 3),X XOR(X + 1)将为<4。
对于X XOR(X + 2)为> = 4,通过添加2来更改了第三低位。这意味着,X以011、010、111或110结尾。因此,我们现在有了X%4 = 3或X%4 = 2。
对于X Xor(X + 3)为> = 4,通过添加3来更改了第三低位。这意味着X以011、010、001、111、110、101结尾。 %4 = 3,X%4 = 2或X%4 = 1。
这是伪代码:
for each element in array:
count[element] += 1
total += 1
for each X in sorted keys of count:
if X % 4 == 3:
answer += count[X + 1] + count[X + 2] + count[X + 3]
if X % 4 == 2:
answer += count[X + 2] + count[X + 3]
if X % 4 == 1:
answer += count[X + 3]
total -= count[X]
answer += total - (count[X + 1] + count[X + 2] + count[X + 3]) # all X + 4 + K work
要考虑重复项,我们需要避免将数字对自己进行计数。您将需要保留每个数字的计数,并做与上述相同的修改,答案将是该数字的计数*(所有其他数字-X + 2个数字的数量)
答案 1 :(得分:0)
您应该致力于分离代码,一种改进是使用set
以避免重复操作,尽管这样做可能会增加内存开销。
import random
from operator import xor
import itertools
random.seed(10)
in_values = [random.randint(0, 10) for _ in range(100)]
def get_pairs_by(condition, values):
odds = set(filter(lambda x: x % 2 == 0, values))
evens = set(filter(lambda x: x % 2 == 1, values))
def filter_pairs_by_condition(values):
return (
(x, y) for x, y in set(
map(lambda x: tuple(sorted(x)),
itertools.product(iter(values), iter(values))))
if condition(xor(x, y))
)
return list(
itertools.chain.from_iterable(
(filter_pairs_by_condition(x) for x in (odds, evens))
)
)
print(get_pairs_by(lambda x: x >= 4, in_values))
关键点是:
set(map(lambda x: tuple(sorted(x)),
itertools.product(iter(values), iter(values)))))
我们正在做的是应该将(5,7)和(7,5)对评估为相同,因此我们在此处将其排除掉。
这里有live example
编辑: 为了快速更新您的代码,您可以使用字典来记忆先前计算的对,因此:
n = int(raw_input()) #array size
ar = map(int, raw_input().split()) #the array
cnt = 0
prev_computed = {}
for i in xrange(len(ar)):
for j in xrange(i+1, len(ar)):
if any(x in prev_compued for x in ((ar[i], ar[j]), (ar[j], ar[i]))):
cnt += 1
continue
if ar[i] ^ ar[j] >= 4 and (not ar[i] & 1 and not ar[j] & 1):
cnt += 1; #print ar[i],ar[j],ar[i]^ar[j];
prev_computed[(ar[i], ar[j])] = True
prev_computed[(ar[j], ar[i])] = True
elif ar[i] ^ ar[j] >= 4 and (ar[i] & 1 and ar[j] & 1):
cnt += 1
prev_computed[(ar[i], ar[j])] = True
prev_computed[(ar[j], ar[i])] = True
print cnt
答案 2 :(得分:0)
def xor_sum(lst)
even_dict = a dictionary with keys being all even numbers of lst and values being their frequencies
odd_dict = a dictionary with keys being all odd numbers of lst and values being their frequencies
total_even_freq = sum of all frequencies of even numbers
total_odd_freq = sum of all frequencies of odd numbers
even_res = process(even_dict, total_even_freq)
odd_res = process(odd_dict, total_odd_freq)
return even_res + odd_res
def process(dict, total_freq)
res = 0
for num in dict.keys
# LSB of XOR of 2 even numbers is always 0
# Let p = XOR of 2 even numbers; if p < 4 then p = 00000000 (minus_2) or 00000010 (plus_2)
plus_2 = num+2
minus_2 = num-2
count = 0
if( (plus_2 XOR num) < 4 and (plus_2 is a key of dict) )
count = count + frequency_of_plus_2
if( (minus_2 XOR num) < 4 and (minus_2 is a key of dict) )
count = count + frequency_of_minus_2
count = count + num
res = res + (total_freq+1-count)
return res
复杂度:
假设您的hash function
(一个dictionaries
)有一个不错的hashmap
,则平均时间复杂度为O(n)