作为输入,一个有序浮点数组,我需要找到每个(i,j)
的{{1}}对A[i]*A[j]>=A[i]+A[j]
的总数。
我已经知道了天真的解决方案,在其他循环中使用循环,这将给我O(n ^ 2)算法,但我想知道是否有更优化的解决方案。
答案 0 :(得分:8)
这是一个O(n)
算法。
让我们看一下A * B >= A + B
。
当A, B <= 0
时,它始终是真的。
当A, B >= 2
时,它始终是真的。
当A >= 1, B <= 1
(或B >= 1, A <= 1
)时,它始终为假。
当0 < A < 1, B < 0
(或0 < B < 1, A < 0
)时,它可以是true或false。
当1 < A < 2, B > 0
(或1 < B < 2, A > 0
)时,它可以是true或false。
这是一个可视化,由Wolfram Alpha和Geobits提供:
现在,进入算法。
*要查找一个数字介于0和1或1和2之间的对,我会执行与the 3SUM problem相似的操作。
*“选择2”这里指的是combinations。
计算两者都为负数的所有对
进行二元搜索以找到第一个正数(&gt; 0)数字的索引 - O(log n)
。
由于我们有索引,我们知道有多少数字是负数/零,我们只需要选择其中的2个,这样就是amountNonPositive * (amountNonPositive-1) / 2
- O(1)
。
查找一个介于0和1之间的所有对
进行二元搜索以找到最后一个数字的索引&lt; 1 - O(log n)
。
从该索引开始作为右索引,最左边的元素作为左索引。
重复此操作,直到右侧索引&lt; = 0 :(在O(n)
中运行)
虽然产品小于总和,但减少左侧索引
计算大于左侧索引的所有元素
减少正确的指数
查找1到2之间的所有对
进行二元搜索以查找第一个数字的索引&gt; 1 - O(log n)
。
从该索引开始,作为左索引,最右边的元素作为右索引。
重复此操作,直到左侧索引&gt; = 2 :(在O(n)
中运行)
虽然产品大于总和,但减少正确的指数
计算大于正确索引的所有元素
增加左侧索引
使用两个数字&gt; = 2
计算所有对在最后一步结束时,我们处于第一个索引&gt; = 2。
现在,从那里,我们只需要选择所有剩余数字中的2个,
所以它再次amountGreaterEqual2 * (amountGreaterEqual2-1) / 2
- O(1)
。
答案 1 :(得分:1)
您可以在O(n log n)
中找到并打印对(以简写形式)。
对于每个A[i]
,满足条件(1)的最小数量k
。
所有大于k的值也将满足条件。
使用二分搜索找到最低j
A [j]&gt; = k为O(log n)
。
所以你可以找到并打印出这样的结果:
(i, j)
(1, no match)
(2, no match)
(3, >=25)
(4, >=20)
(5, >=12)
(6, >6)
(7, >7)
...
(n-1, n)
如果要打印所有组合,则为O(n ^ 2),因为组合数为O(n ^ 2)。
(*)要处理负数,它实际上需要更复杂一些,因为满足等式的数字可能超过一个范围。 我并不完全确定它对于小的负数如何表现,但如果范围的数量不是绝对有限,那么我的解决方案不再优于O(n ^ 2)。
答案 2 :(得分:1)
这是二分搜索,O(n log n):
A*B = A+B
处的每个号码都有一个断点。您可以将其减少到B = A / (A - 1)
。一侧或另一侧的所有数字都适合它。如果有负数等没关系
如果A < 1
,那么所有数字<= B
都适合。
如果A > 1
,那么所有数字>= B
都适合。
如果A == 1
,则没有匹配(除以零)。
所以有些伪代码:
loop through i
a = A[i]
if(a == 1)
continue
if(a >= 2)
count += A.length - i
continue
j = binsearch(a / (a-1))
if(j <= i)
continue
if(a < 1)
count += j-i
if(a > 1)
count += A.length - j
答案 3 :(得分:0)
这是一个O(n)
算法,可以在数组元素为正时解决问题。
当元素为正数时,我们可以这样说:
A[i]*A[j] >= A[i]+A[j]
时j>i
A[k]*A[j] >= A[k]+A[j]
,k
k>i
满足A[i]*A[j] < A[i]+A[j]
(因为数组已排序)。
如果j>i
A[i]*A[k] < A[i]+A[k]
k
,k<j
int findNumOfPairs(float A[])
{
start = 0;
end = A.length - 1;
numOfPairs = 0;
while (start != end)
{
if (A[start]*A[end] >= A[start]+A[end])
{
numOfPairs += end - start;
end--;
}
else
{
start++;
}
}
return numOfPairs;
}
满足{{1}}。
(当两个数字都是分数时,这些事实不成立,但无论如何都不会满足条件)
因此我们可以执行以下算法:
{{1}}
答案 4 :(得分:-1)
如果排除所有小于1.0的浮点数,因为任何数字倍数小于1,x * 0.3 = A [i] + A [j],每个i <1。 j,所以我们只需要计算数组的数量来计算对的数量(i,j),我们可以使用关于排列和组合的公式来计算它。公式应为n(n-1)/ 2。