我试图解决对和问题,即给定一个排序数组,如果存在两个索引i
和j
,那么i!=j
和a[i]+a[j] == k
一些k
。
执行相同问题的方法之一是运行两个嵌套for循环,导致O(n*n)
的复杂性。
另一种解决方法是使用两种指针技术。我无法使用两个指针方法解决问题,因此查找它但无法理解为什么它的工作原理。我如何证明它有效?
#define lli long long
//n is size of array
bool f(lli sum) {
int l = 0, r = n - 1;
while ( l < r ) {
if ( A[l] + A[r] == sum ) return 1;
else if ( A[l] + A[r] > sum ) r--;
else l++;
}
return 0;
}
答案 0 :(得分:8)
好吧,这样想吧:
你有一个排序数组(你没有提到数组已经排序,但对于这个问题,通常就是这种情况):
{-1,4,8,12}
算法首先选择数组中的第一个元素和最后一个元素,将它们加在一起并将它们与你追求的总和进行比较。
如果我们的初始金额与我们正在寻找的金额匹配,那就太棒了!!如果没有,那么,我们需要继续查看可能的金额大于或小于我们开始的金额。通过从数组中的最小值和最大值开始,我们可以将其中一个元素作为可能解决方案的一部分。
让我们说我们正在寻找总和3.我们看到3&lt; 11.由于我们的大数(12)与最小可能数(-1)配对,我们的总和太大这一事实意味着12不能成为任何可能解决方案的一部分,因为使用12的任何其他总和必须是大于11(12 + 4> 12 - 1,12 + 8> 12 - 1)。
所以我们知道我们不可能在数组中使用12 +另外一个数字来得到3的总和,它们都会太大了。因此,我们可以通过向下移动到下一个最大数字8来消除12个搜索。我们在这里做同样的事情。我们看到8 + -1仍然太大,所以我们向下移动到下一个数字4,瞧!我们找到了匹配。
如果我们得到的总和太小,同样的逻辑适用,我们可以消除我们的小数字,因为我们使用当前最小数字得到的任何总和必须小于或等于我们与它配对时得到的总和我们目前最大的数字。
我们一直这样做,直到我们找到一个匹配,或直到索引相互交叉,因为在它们交叉之后,我们只是添加我们已经检查过的数字对(即4 + 8 = 8 + 4)。
这可能不是一个数学证明,但希望它说明算法是如何工作的。