假设我们有一个数组C,其中包含C中的所有元素> 0
如果(a, b)
和0 ≤ a < b < N
,则一对索引C[a] * C[b] ≥ C[a] + C[b]
可以成倍增加。
时间复杂度是O(n)
感谢您帮助支持此案例。 感谢。
答案 0 :(得分:9)
O(N)解决方案就在这里。
假设数组中的元素按非递减顺序排序。 如果数组未排序,那么最差时间复杂度O(N)是不可解密的。
原始条件C[a] * C[b] ≥ C[a] + C[b]
可以很容易地表达为C[b] ≥ C[a] / (C[a] - 1)
所以,看看C[a] / (C[a] - 1)
...
......我们可以看到:
0 ≤ C[a] < 1
,那么(a, b)
只有在C[a] = 0
1 < C[a] < 2
,则为C[a] / (C[a] - 1) > 2
,因此C[b] > 2
。所以,C[b] > C[a]
,但这是不可能的,因为C[a] ≥ C[b]
(因为数组已排序)。C[a] > 2
,则该对可以乘以C[b]
C[b] ≥ C[a] / (C[a] - 1)
醇>
因此,C#中的代码可能如下所示:
int count_pairs(double[] C)
{
int result = 0;
int len = C.Length;
if (len > 1)
{
int lo_index;
int hi_index = len - 1;
// Skip all C[i] less than 1
for (lo_index = 0; lo_index < len; lo_index++)
{
if (C[lo_index] > 1)
break;
}
while (hi_index > lo_index)
{
double v = C[hi_index] / (C[hi_index] - 1);
while (lo_index < hi_index && C[lo_index] < v)
{
lo_index++;
}
if (lo_index == hi_index)
break;
result += (hi_index - lo_index);
hi_index--;
}
}
return result;
}
答案 1 :(得分:3)
与竞争问题一样,您必须在编码之前解决问题。在这种情况下,你需要一些基本的代数。我会忽略奇怪的数字格式,只能在C
上运行。
因此,给定非负数a
,非负数b
会产生a * b >= a + b
吗?
a * b >= a + b
=&gt; b * (a-1) >= a
现在,我们有4个案例:
b <= a / (a-1)
。请注意,RHS为负数,而b
为非负数。因此没有这样的b
-b >= 0
,因此,因为b是非负数, b == 0 b * 0 >= 1
,简化为 false 。因此,没有此类b
b >= a / (a-1)
。这是唯一的非平凡案例。 这本身就已经给你一个O(N * log(N))算法:
通过数组迭代保持总和。对于每个数字,如果为0,则在数组中找到0的数量并将它们添加到总和中。如果它是0 < num
&lt; = 1,添加0.如果是&gt; 1,添加值的数量&gt; = num / (num-1)
。 由于数组是升序的,您可以使用二进制搜索在log(N)
时间中查找这些值,从而为您提供总N * log(N)
最差运行时(和O(N)
最佳运行时,如果所有值都是noops - 介于0和1之间
为了使算法进一步优化到O(N)的最后一步,您需要观察函数x / (x-1)
在x&gt;时的行为。 1和x正在增长(即,当您遍历数组时,搜索目标是什么)。
答案 2 :(得分:2)
我正在做同样的挑战。看起来您忘记了多个输入为0的情况,因为0 * 0 = 0 + 0;
class Solution {
public static final long ONE_MILLION = 1000000;
public static final int LIMIT = 1000000000;
public int solution(int[] A, int[] B) {
// need to redo algebra term is such that B >= A/A-1
//so if A < 1 only possible if C[a] =0 and C[b] = 0
//if A < 2 is impossible since sorted
//if A > possible
if (A.length < 2) { return 0;}
int numberOfMP = 0;
int lowIndex = 0;
int highIndex = A.length-1;
if (A[0] == 0 && B [0] == 0) {
int index = 1;
int increaseAmount = 1;
while (A[index] == 0 && B[index] == 0) {
numberOfMP += increaseAmount;
increaseAmount++;
}
}
while(lowIndex < highIndex){
//don't convert to double to avoid precision errors
long C_low = convertValue(A[lowIndex], B[lowIndex]);
long C_high;
//avoid useless calculations for values we already know will fail
if(C_low >= ONE_MILLION) {
C_low = convertValue(A[lowIndex], B[lowIndex]);
C_high = convertValue(A[highIndex], B[highIndex]);
//note that since both inputs to the product were scaled, we need to scale the sum twice
//not a scaleable solution...
if( C_low * C_high >= (C_low + C_high) * ONE_MILLION) {
numberOfMP += highIndex - lowIndex;
highIndex--;
}else{
lowIndex++;
}
}else{
lowIndex++;
}
}
if (numberOfMP > LIMIT) {
return LIMIT;
}
return numberOfMP;
}
private long convertValue(int a, int b) {
return (long) a * ONE_MILLION + (long) b;
}
}
答案 3 :(得分:1)
这是我测试的O#N解决方案的C#版本。
注意:我的练习有点复杂。
传入参数包含N
(0..100,000)
个非负数,其中A
数组包含数字(0..1,000)
的整数部分,B
数组包含小数数字(0..999,999)
的一部分。
由A
和B
数组表示的数字按非递减顺序排序。
如果对的数量大于1,000,000,000
,则该函数应返回1,000,000,000
。
class Solution
{
public int solution(int[] A, int[] B)
{
// a == 0 => b == 0
// 0 < a < 1 => no b
// a == 1 => no b
// 1 < a => b >= a / (a - 1)
if (A.Length < 2)
{
return 0;
}
int result = 0;
int currentIndex = 0;
int maxIndex = A.Length - 1;
const int OneMillion = 1000000;
const int OneBillion = 1000000000;
// Counting zeros
while (currentIndex < A.Length && A[currentIndex] == 0 && B[currentIndex] == 0)
{
currentIndex++;
}
// Adding number of pairs of zeros
if (currentIndex > 1)
{
// n = currentIndex - 1
// sum(1..n) => (n + 1) * (int)(n / 2) + (n % 2) * (int)((n + 1) / 2)
decimal n = new Decimal(currentIndex - 1);
decimal numberOfPairsOfZeros = (n + 1) * (int)(n / 2) + (n % 2) * (int)((n + 1) / 2);
result += (numberOfPairsOfZeros > OneBillion ? OneBillion : (int)numberOfPairsOfZeros);
if (result >= OneBillion)
{
return OneBillion;
}
}
if (currentIndex == A.Length)
{
return result;
}
// Skip values where 0 < A.B <= 1.001000
// 1.001000 can be in pair with numbers >= 1001.000000 but the maximum number is 1000.999999;
// 1.001001 can be in pair with numbers >= 1000.000999;
while
(
currentIndex < A.Length
&&
(
A[currentIndex] == 0
||
(
A[currentIndex] == 1
&& B[currentIndex] < 1001
)
)
)
{
currentIndex++;
}
if (currentIndex == A.Length)
{
return result;
}
// From this point 1 < A.B, so we look for A2.B2 values where A2.B2 >= A.B / (A.B - 1)
for (int i = currentIndex; i < A.Length - 1; i++)
{
// number between 1.001001 and 2 should be searched only
if (A[i] == 1)
{
// Search numbers greater than or equals to A.B / (A.B - 1)
// A.B / (A.B - 1) = 1.B / (1.B - 1) = 1.B / 0.B = 1 / 0.B + 1
double scaledOnePerBFractionalPart = (double)OneMillion / (double)B[i] * (double)OneMillion;
int scaledMinValue = (int)scaledOnePerBFractionalPart + OneMillion + (Math.Ceiling(scaledOnePerBFractionalPart) == scaledOnePerBFractionalPart ? 0 : 1);
while (maxIndex > i && OneMillion * A[maxIndex] + B[maxIndex] >= scaledMinValue)
{
maxIndex--;
}
result += A.Length - 1 - maxIndex;
}
else
{
// In this case the number is greater than or equal to 2.
// So we just add the remaining indexes as number of pairs.
result += A.Length - 1 - i;
}
if (result >= OneBillion)
{
return OneBillion;
}
}
return result >= OneBillion ? OneBillion : result;
}
}
答案 4 :(得分:0)
以下条件:
如果0≤P<1,则一对指数(P,Q)是乘法的。 Q&lt; N和C [P] * C [Q]≥C[P] + C [Q]。
结合预先排序的数组:
- 从数组创建的实数按非递减顺序排序。
醇>
允许O(n)解决方案。也许如果您通过解决方案调试,您将看到一种模式。
答案 5 :(得分:0)
针对示例质询的Java解决方案,可读性略高:
recover
答案 6 :(得分:-1)
假设数组中的元素按非递减顺序排序 我在JavaScript中的O(N)解决方案:
function solution(A, B) {
var scale = 1000000;
var N = A.length;
var count=0;
var left = 0;
var right = N-1;
var C_left = 0;
while(left<right){
//to avoid rounding errors, use multiplication
C_left = A[left]*scale+B[left];
if(C_left>=scale){
if(C_left*(A[right]*scale+B[right])>=(C_left+(A[right]*scale+B[right]))*scale){
// if C[left],C[right] is ok, that means that all elements C[left++],C[right] to satisfy condition
count+=right-left;
right--;
}else{
left++;
}
}else{
left++;
}
}
//condition from codility.com test
if(count>1000000000)
return 1000000000;
else{
return count;
}
}
答案 7 :(得分:-1)
我不是在这里复制我的算法,但我的想法似乎也是O(n)。
1,首先计算最小可能的完整图。 将排序后的数组除以2(在中间索引处) - 向上舍入(所以它是左倾树)
并检查第一个元素和最后一个元素,增加第一个索引直到没有通过 - 计算完整图形的边缘 - n *(n-1)/ 2
如果我们没有通过它是O(N)最坏的情况。并且我们不依赖于N存储任何东西,只需2-3个临时int来计算差异(CP * CQ) - (CP + CQ)应该>&gt; = 0
2,删除所有未通过的边缘
所以我们在1)中得到了一个传球,继续检查,但是下一个元素,而不是最后一个,直到我们得到一个传球。每次迭代都会减少第一个结果 - 从完整图中删除,然后返回结果。
2)继续算法,这意味着O(N)最坏情况已经分布在1)和2)之间
不幸的是我只是测试了自己,但不会通过这个测试,因为它至少花了我3个小时。:(