我正在研究代码挑战问题 - “找到幸运的三元组”。 “幸运三元组”定义为“在列表lst
中,适用于(lst[i], lst[j], lst[k]) where i < j < k
三元组合的任意组合,其中lst[i] divides lst[j]
和lst[j] divides lst[k]
。
我的任务是找到给定列表中的幸运三元组数。蛮力方式是使用三个循环,但解决问题需要太多时间。我写了这个,系统响应“时间超过”。问题看起来很愚蠢,但数组是未排序的,因此二进制搜索等常规方法不起作用。我对这个问题感到震惊了一天,希望有人能给我一个提示。我正在寻找一种更快解决问题的方法,至少时间复杂度应该低于O(N ^ 3)。
答案 0 :(得分:4)
一个简单的动态编程算法将在二次时间和线性空间中执行此操作。您只需为列表中的每个项目维护一个计数器c[i]
,该计数器代表除L[i]
之前的整数。
然后,当您浏览列表并使用之前的所有项L[k]
测试每个整数L[j]
时,如果L[j]
除以L[k]
,则只需添加c[j]
(可能是0)到你的三元组的全局计数器,因为这也意味着确实存在c[j]
项L[i]
,L[i]
除L[j]
和{{1} }}
i < j
可能有一些更好的算法使用花哨的离散数学来更快地完成它,但如果O(n ^ 2)没问题,这样就可以了。
关于你的评论:
为什么选择DP?我们有一些东西可以清楚地建模为具有从左到右的顺序(DP橙色标志),感觉就像重复使用先前计算的值可能很有趣,因为强力算法会进行很多次完全相同的计算。
如何从中获得解决方案?运行一个简单的例子(提示:最好是从左到右处理输入)。在步骤int c[] = {0}
int nbTriples = 0
for k=0 to n-1
for j=0 to k-1
if (L[k] % L[j] == 0)
c[k]++
nbTriples += c[j]
return nbTriples
,计算您可以从此特定点计算的内容(忽略i右侧的所有内容),并尝试查明您为不同i
反复计算的内容:这就是您想要缓存。在这里,当您在步骤i's
(k
)看到潜在的三元组时,您必须考虑L[k] % L[j] == 0
上发生的情况:“左侧是否有一些除数?这些中的每一个都会给我们一个新的三元组。让我们看看......但是等等!我们已经在步骤L[j]
上计算了它!让我们缓存这个值!“这就是你跳上座位的时候。
答案 1 :(得分:2)
python中的完整工作解决方案:
c = [0] * len(l)
print c
count = 0
for i in range(0,len(l)):
j=0
for j in range(0, i):
if l[i] % l[j] == 0:
c[i] = c[i] + 1
count = count + c[j]
print j
print c
print count
'
答案 2 :(得分:1)
阅读Sieve of Eratosthenes,这是一种寻找素数的常用技巧,可以用来找到你的幸运三元组#39。基本上,您需要按递增的值顺序迭代列表,并且对于每个值,将其乘以增加因子,直到它大于最大的列表元素,并且每次这些倍数中的一个等于列表中的另一个值时,倍数可以被基数整除。如果列表在给你时被分类,那么i&lt; j&lt; k要求也将得到满足。
e.g。给出列表[3, 4, 8, 15, 16, 20, 40]
:
从3
开始,其在列表范围内具有倍数[6, 9, 12, 15, 18 ... 39]
。在这些倍数中,列表中只包含15
,因此在15
下记录它具有因子3
。
继续4
,其中有[8, 12, 16, 20, 24, 28, 32, 36, 40]
倍数。将那些标记为因子4。
继续浏览列表。当您到达具有现有已知因子的元素时,如果您在列表中找到该数字的任何倍数,那么您将获得三倍。在这种情况下,对于16
,它在列表中有多个32
。现在您知道32
可以被16
整除,可以被4
整除。鉴于15
,列表中没有倍数,因此没有值可以与3
和15
形成三元组。
答案 3 :(得分:1)
问题的precomputation
步骤可以帮助减少时间复杂性。
预计算步骤:
对于每个元素(i),迭代数组以找到哪些元素(j),使lst[j]%lst[i]==0
for(i=0;i<n;i++)
{
for(j=i+1;j<n;j++)
{
if(a[j]%a[i] == 0)
// mark those j's. You decide how to store this data
}
}
此预计算步骤将花费O(n^2)
时间。
在终极步骤中,使用预计算步骤的详细信息,以帮助查找三元组..
答案 4 :(得分:0)
形成一个图形 - 一个索引数组,它是当前索引之前的倍数。然后计算这些指数的倍数的集体总和,从图中引用。它的复杂度为 O(n^2)
例如,对于列表 {1,2,3,4,5,6} 将有一个倍数数组。图表看起来像 { 0:[1,2,3,4,5], 1:[3,5], 2: [5], 3:[],4:[], 5:[]}
因此,三胞胎总数将为 {0->1 ->3/5} 和 {0->2 ->5},即 3
package com.welldyne.mx.dao.core;
import java.util.LinkedList;
import java.util.List;
public class LuckyTriplets {
public static void main(String[] args) {
int[] integers = new int[2000];
for (int i = 1; i < 2001; i++) {
integers[i - 1] = i;
}
long start = System.currentTimeMillis();
int n = findLuckyTriplets(integers);
long end = System.currentTimeMillis();
System.out.println((end - start) + " ms");
System.out.println(n);
}
private static int findLuckyTriplets(int[] integers) {
List<Integer>[] indexMultiples = new LinkedList[integers.length];
for (int i = 0; i < integers.length; i++) {
indexMultiples[i] = getMultiples(integers, i);
}
int luckyTriplets = 0;
for (int i = 0; i < integers.length - 1; i++) {
luckyTriplets += getLuckyTripletsFromMultiplesMap(indexMultiples, i);
}
return luckyTriplets;
}
private static int getLuckyTripletsFromMultiplesMap(List<Integer>[] indexMultiples, int n) {
int sum = 0;
for (int i = 0; i < indexMultiples[n].size(); i++) {
sum += indexMultiples[(indexMultiples[n].get(i))].size();
}
return sum;
}
private static List<Integer> getMultiples(int[] integers, int n) {
List<Integer> multiples = new LinkedList<>();
for (int i = n + 1; i < integers.length; i++) {
if (isMultiple(integers[n], integers[i])) {
multiples.add(i);
}
}
return multiples;
}
/*
* if b is the multiple of a
*/
private static boolean isMultiple(int a, int b) {
return b % a == 0;
}
}