我对经典的两和问题有一个O(n ^ 2)解。其中A [1 ... n]排序正整数数组。 t是一些正整数。
需要表明A包含两个不同的元素a和b s.t. a + b = t
到目前为止,这是我的解决方案:
t = a number;
for (i=0; i<A.length; i++)
for each A[j]
if A[i] + A[j] == t
return true
return false
如何使其成为线性解决方案? O(n)试图弄清楚我的头脑。
到目前为止,这是我想到的一种方法。我将在A的开头开始,j将在A的结尾开始。我将增加,j将减少。所以我在for循环中有两个计数器变量,i&amp;学家
答案 0 :(得分:2)
有很多方法可以改进。
t = a number for (i = 0; i < A.length; i++) j = binarySearch(A, t - A[i], i, A.length - 1) if (j != null) return true return false
二进制搜索是通过O(log N)步骤完成的,因为你对数组中的每个元素执行二进制搜索,整个算法的复杂性将是O(N * log N) 这已经是对O(N ^ 2)的巨大改进,但你可以做得更好。
1 3 4 8 9
现在两个指针的总和是1 + 9 = 10。 10小于所需的和(11),没有办法通过移动T指针达到所需的总和,所以我们将H指针向右移动:
1 3 4 8 9
3 + 9 = 12大于所需的总和,没有办法通过移动H指针达到所需的总和,向右移动将进一步增加总和,向左移动它将我们带到初始状态,所以我们将T指针向左移动:
1 3 4 8 9
3 + 8 = 11&lt; - 这是所需的总和,我们已经完成了。
因此算法的规则包括向左移动H指针或向右移动T指针,当两个指针的总和等于所需的总和,或者H和T交叉时,我们就完成了(T变小了比H)。
t = a number
H = 0
T = A.length - 1
S = -1
while H < T && S != t
S = A[H] + A[T]
if S < t
H++
else if S > t
T--
return S == t
很容易看出这个算法在O(N)运行,因为我们最多遍历每个元素一次。
答案 1 :(得分:0)
你创建了2个包含索引0和索引n-1的新变量,让我们分别称它们为i和j。 然后,检查A [i]和A [j]的总和,如果和小于t,则增加i(较低的索引),如果它大,则减小j(较高的索引)。继续,直到你找到i和j这样A [i] + A [j] = t所以你返回true,或者j&lt; = i,你返回false。
int i = 0, j = n-1;
while(i < j) {
if(A[i] + A[j] == t)
return true;
if(A[i] + A[j] < t)
i++;
else
j--;
return false;
答案 2 :(得分:0)
鉴于A [i]相对较小(可能小于10 ^ 6),您可以创建一个大小为10 ^ 6的数组B,每个值等于0.然后应用以下算法:
for i in 1...N:
B[A[i]] += 1
for i in 1...N:
if t - A[i] > 0:
if B[t-A[i]] > 0:
return True
编辑:好吧,既然我们知道数组已经排序,那么找到另一种算法可能会更明智。我会在这里留下答案,因为它仍适用于某类相关问题。