给定一组数字,生成所有唯一对。
例如,给定[ 1, 2, 3, 4, 5 ]
,唯一的数字对将是:
(1, 2), (1, 3), (1, 4), (1, 5)
(2, 3), (2, 4), (2, 5)
(3, 4), (3, 5)
(4, 5)
我的解决方案如下:
int[] numbers = new int[] { 1, 2, 3, 4, 5 };
HashSet<Pair> pairs = new HashSet<Pair>();
for(int i = 0; i < numbers.Length; i++)
{
for(int j = i + 1, j < numbers.Length; j++)
{
pairs.Add(new Pair(numbers[i], numbers[j]));
}
}
我认为时间复杂度看起来像O(n 2 - 1)减去1,因为j
的迭代总是比i
<1短< / em>的
对这类问题进行了一些研究之后,我找不到任何明确的答案,以确定是否可以更快地完成。有没有比O(n 2 -1)更好的解决方案?
答案 0 :(得分:41)
思考问题的方法之一是解决问题的更快方法&#34;是为某些特定格式(你认为&#34;可能是最大/最难解决的#34;)来查看输出的大小。
如果输出为O(n^2)
,那么您无法比O(n^2)
更快地解决问题,因为您必须为每个输出花费至少O(1)
。
你可以看到那里的模式,如果你有5个格式[1, 2, 3, 4, 5]
的数字,那么唯一的一对
4 pairs in first row
3 pairs in second row
2 pairs...
1 pair
因为它们看起来像
(1, 2), (1, 3), (1, 4), (1, 5)
(2, 3), (2, 4), (2, 5)
(3, 4), (3, 5)
(4, 5)
如果数组中有20个变量(格式为[1, 2, 3,... 18, 19, 20]
),则如下:
19 pairs
18 pairs
...
2 pairs
1 pair
因此输出大小为(n-1) + (n-2) + (n-3) ... + 3 + 2 + 1
。你必须总结它(看看如何对系列求和),结果是O(n^2)
证实了什么?
最糟糕的情况是至少O(n^2)
。
另请注意,此时此刻,我们并不知道真正的最坏情况复杂性 - 算法可能更慢(我们只是发现某些输入需要O(n^2)
)。我们确信至少这些数据需要O(n^2)
。对于不同的输入,它可以更快或更慢。
Conlusion :我们已经证明该算法至少花费O(n^2)
时间(最坏情况),您创建的算法最多运行O(n^2)
时间(如spyc post中所述)=你有最佳算法。
OP解决方案的额外信息:
使用HashSet检测冲突只是&#34; pseudoConstant&#34;并且仅适用于小数字和&#34;一些运气&#34;。大量数字需要O(n)
。因此,您最终可以输入n^2
输出,并且每个输出都需要n
来处理,这会导致n^3
复杂性。
您可以通过预处理任务来解决它:
1)对其进行排序 - 只需n log n
,因此不会影响n^2
2)删除重复两次以上[1, 3, 3, 3, 5] -> [1, 3, 3, 5]
的数字,O(n)
3)然后使用您的算法进行此更新:
3.1)在for i
周期开始时:if (number[i] == number[i-1]) continue;
3.2)在for j
周期开始时:记住最后一对。添加新对时,请查看最后一对并检查它是否相同。如果是这样 - continue;
示例:
Input: [1, 3, 3, 5]
1)i=0, j=1, number[0]=1, number[1]=3 -> add (1, 3)
2)i=0, j=2, number[0]=1, number[2]=3 -> same as last pair, use continue
3)i=0, j=3, number[0]=1, number[3]=5 -> add (1, 5)
4)i=1, j=2, number[1]=3, number[2]=3 -> add (3, 3)
5)i=1, j=3, number[1]=3, number[3]=5 -> add (3, 5)
6)i=2, before go to j-cycle, check number[i] === number[i-1] It is true, use continue
答案 1 :(得分:12)
如下:
first for loop - O(n)
second for loop - O(n-1)
最佳时间复杂度:
您还可以使用二项式系数进行排列,以获得某个字符串的排列数。例如:
如果你有6个数字 {0,1,2,3,4,5} (n = 6),你想知道你可以做出多少种不同的排列,即:( 3,5),(5,3)等...然后(k = 2,每组两位数),排列量将是:
不同的排列,请注意虽然在这种情况下(3,5),(5,3)是单独计算的,所以它的顺序都很重要。如果您希望将(5,3)和(3,5)计为一个组合,则公式如下:
static long factorial(long x) // calcs the factorial TimeCmplx = O(n)
{
if (x == 1)
return x;
return x * factorial(x - 1);
}
static long permutations(long n , long k) //Check that (n , k) >= 0
{
// Permutations , n!/(n-k)!
return factorial(n) / factorial(n - k);
}
答案 2 :(得分:5)
我认为时间复杂度看起来像O(n2 - 1)减去1,因为j的iteraton总是比i短1
如果它很重要(big-O-notation通常只会写出增长最快的术语),那么你会在[0,n]上迭代i,每个包含j超过[i + 1,n]的迭代所以迭代次数是(n∙(n-1))/ 2而不是n²-1。
此外,您的编辑更改为HashSet而不是列表更改最坏情况执行,但不是amortised value - 如果Pair.GetHashCode()始终返回相同的值,您已将其提升到O (n³),如在碰撞是常见的情况下,哈希集插入变为O(n)而不是常数。
答案 3 :(得分:0)
这是三角形算法的区域。
您有 N 输入,并且您希望输出三角形。
您的输出三角形的高度 N-1 且宽度 N-1 。< / p>
Area of a triangle = height * width / 2
= (N-1) * (N-1) / 2
= (N^2 - 2N + 1) / 2
O(n^2 - n)
始终是最低/最佳算法费用!