Arrays 确定A+;B=C存在于n个整数的数组中
这是我的一个朋友的家庭作业(在算法和数据结构课程中)中遇到的一个问题。他问我这件事。然而,我无法解决这个问题,在过去的几天里,我已经思考了一段时间 在[0231-1]范围内有n个随机整数(可能有重复的。确定这些数字中的3个是否满足A+B=C) 我首先提出了一个简单的算法,就是O(n2logn)。 然后我提出了一个算法,即O(n2)。下面是伪代码:Arrays 确定A+;B=C存在于n个整数的数组中,arrays,algorithm,integer,linear-algebra,Arrays,Algorithm,Integer,Linear Algebra,这是我的一个朋友的家庭作业(在算法和数据结构课程中)中遇到的一个问题。他问我这件事。然而,我无法解决这个问题,在过去的几天里,我已经思考了一段时间 在[0231-1]范围内有n个随机整数(可能有重复的。确定这些数字中的3个是否满足A+B=C) 我首先提出了一个简单的算法,就是O(n2logn)。 然后我提出了一个算法,即O(n2)。下面是伪代码: sort(a); // non-descending for (i = 0; i < n; i++) { j = i; k = i + 1;
sort(a); // non-descending
for (i = 0; i < n; i++) {
j = i; k = i + 1;
while (j < n && k < n) {
if (a[i] + a[j] == a[k])
return true;
else if (a[i] + a[k] < a[j])
k++;
else
j++;
}
}
return false;
排序(a);//非降序
对于(i=0;i
然而,问题表明,1
O(n^2)
算法(包括您的算法)都会运行得非常快。事实上,实际复杂性将是O(n*logn)
(排序的复杂性)。这很像快速排序,我们有
O(n*logn)
average和一个很小的命中O(n^2)
10^6
随机数给我们提供了~10^6*10^6
范围内的“几乎随机”和~0..10^9
。其中一个10^12
随机和等于整数范围内给定随机值的几率有多大?非常好。现在,这些
10^12
随机和中的一个等于给定随机值10^6中的一个的概率有多大?100%,诗意地说
我已经实现了您提出的解决方案,因为n=10^6
它在最内部的循环中平均执行5000-10000
操作。对于O(n^2)
,就到此为止。排序是其中最昂贵的操作
另外,如果您将解决方案更新为使用散列而不是排序,则可以进一步降低复杂性,使其更均匀
用java编写的测试程序,供参考。运行它,自己看看
int n = 1000000;
int[] a = new int[n];
// generate random array
Random r = new Random();
for (int i = 0; i < n; ++i) {
do {
a[i] = r.nextInt();
} while (a[i] < 0);
}
Arrays.sort(a);
// number of operations inside main loop
int ops = 0;
// main logic, pretty much as OP described it
boolean found = false;
for (int i = 0; i < n && !found; ++i) {
int j = i;
int k = i + 1;
while (k < n) {
++ops;
if (a[i] > a[k] - a[j]) {
++k;
} else if (a[i] < a[k] - a[j]) {
++j;
} else {
System.out.println(a[i] + " + " + a[j] + " = " + a[k]);
found = true;
break;
}
}
}
System.out.println(ops);
int n=1000000;
int[]a=新的int[n];
//生成随机数组
随机r=新随机();
对于(int i=0;ia[k]-a[j]){
++k;
}else如果(a[i]
在Python中使用哈希的算法需要10-900微秒(平均:200中位数:60):
它是O(N**2)
但它似乎足够快
相比之下,创建冻结集的摊销O(N)
操作需要270
毫秒(比搜索慢1000倍),创建随机列表需要0.9
秒
注意:random.sample
如果输入序列包含唯一元素,则不会返回重复的元素,因此frozenset
不会丢弃上述示例中的任何元素。要解决允许重复元素的随机序列的问题,我们应使用两种数据结构:
#!/usr/bin/env python
import random
L = [random.randrange(2**31) for _ in xrange(10**6)]
S = frozenset(L)
print len(L), len(S)
print next(((a, b, a+b) for a in L for b in L if (a + b) in S), None)
输出
一般的问题是,是否有比二次算法更好的算法是公开的
因此,如果您需要更快的算法,您可能需要利用它们是32位的事实。a+B=C,因此
B=C-A或A=C-B
通过使用哈希表,可以在O(n)复杂度下解决上述问题
var C; // the sum you are looking for
for(each element)
X = C - element
boolean exists = lookup for X in hash table
if (exists) combination A+B=C exists in the given input
else hashtable.put(element)
希望这能有所帮助。在对排序列表进行测量时,我得到了O(n log n):
from bisect import bisect_right
import cProfile as prof
import random
def find3sum(T):
if len(T) < 3:
return None
n = len(T)
top = T[-1]
for i in range(len(T)-1):
b = top - T[i]
if b < T[i]:
return None
k = bisect_right(T, b, i, n-1)
while k > i:
c = T[i] + T[k]
j = bisect_right(T, c, k, n-1)
if j <= k:
break
elif T[j] == c:
return (i, k, j)
else:
k -= 1
def test_one(a):
a = sorted(a)
r = find3sum(a)
i, k , j = r
assert a[i] + a[k] == a[j]
def test():
n = 100000
max = 200000
random.seed(0)
for _ in range(100):
a = [random.randint(0,max) for _x in xrange(n)]
test_one(a)
a = range(n)
test_one(a)
prof.run('test()')
从对分导入对分\u右
导入cProfile作为prof
随机输入
def find3sum(T):
如果len(T)<3:
一无所获
n=长度(T)
top=T[-1]
对于范围内的i(透镜(T)-1):
b=顶部-T[i]
如果bi时:
c=T[i]+T[k]
j=对分_右(T,c,k,n-1)
如果j,你有证据表明有一个更快的解决方案O(n^2)?数字排序了吗?如果(a[i]+a[k]var C; // the sum you are looking for
for(each element)
X = C - element
boolean exists = lookup for X in hash table
if (exists) combination A+B=C exists in the given input
else hashtable.put(element)
from bisect import bisect_right
import cProfile as prof
import random
def find3sum(T):
if len(T) < 3:
return None
n = len(T)
top = T[-1]
for i in range(len(T)-1):
b = top - T[i]
if b < T[i]:
return None
k = bisect_right(T, b, i, n-1)
while k > i:
c = T[i] + T[k]
j = bisect_right(T, c, k, n-1)
if j <= k:
break
elif T[j] == c:
return (i, k, j)
else:
k -= 1
def test_one(a):
a = sorted(a)
r = find3sum(a)
i, k , j = r
assert a[i] + a[k] == a[j]
def test():
n = 100000
max = 200000
random.seed(0)
for _ in range(100):
a = [random.randint(0,max) for _x in xrange(n)]
test_one(a)
a = range(n)
test_one(a)
prof.run('test()')
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.002 0.002 183.764 183.764 <string>:1(<module>)
200 0.005 0.000 89.996 0.450 find2sum.py:25(test_one)
1 17.269 17.269 183.762 183.762 find2sum.py:31(test)
200 35.096 0.175 79.601 0.398 find2sum.py:5(find3sum)
10000000 44.958 0.000 52.398 0.000 random.py:160(randrange)
10000000 23.891 0.000 76.289 0.000 random.py:224(randint)
1 0.000 0.000 0.000 0.000 random.py:99(seed)
19599982 44.077 0.000 44.077 0.000 {_bisect.bisect_right}
1 0.000 0.000 0.000 0.000 {function seed at 0x9a1972c}
600 0.001 0.000 0.001 0.000 {len}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
10000000 7.440 0.000 7.440 0.000 {method 'random' of '_random.Random' objects}
301 0.635 0.002 0.635 0.002 {range}
200 10.390 0.052 10.390 0.052 {sorted}