Algorithm 求乘法表中不同数字的个数
灵感来自 假设我有一个nxn乘法表,表上不同值的数目是多少 例如,一个3X3乘法表 1 2 3Algorithm 求乘法表中不同数字的个数,algorithm,Algorithm,灵感来自 假设我有一个nxn乘法表,表上不同值的数目是多少 例如,一个3X3乘法表 1 2 3 2.4.6 369 具有6唯一值,即[1,2,3,4,6,9] 到目前为止,我只有一个O(n2)溶液 public static void findDistinctNumbers(int n) { Set<Integer> unique = new HashSet<>(); for(int i=1; i<=n; i++) { for(
2.4.6
369 具有6唯一值,即[1,2,3,4,6,9] 到目前为止,我只有一个O(n2)溶液
public static void findDistinctNumbers(int n) {
Set<Integer> unique = new HashSet<>();
for(int i=1; i<=n; i++) {
for(int j=1; j<=n; j++) {
unique.add(i*j);
}
}
System.out.println("number of unique values: " + unique.size());
}
公共静态void findDintintNumber(int n){
Set unique=新的HashSet();
对于(inti=1;i来说,问题是要使用一个集合来验证唯一性,必须首先填充它,不管怎样,它都是O(n^2);
没有集合,您无法轻松验证数字是否唯一
作为旁注:因为big-O类有点宽泛(即,它可以描述任何不高于某事物的复杂度,但不一定)
不更低,即线性复杂度和二次复杂度算法都可以描述为O(n^2),因为在这两种情况下,复杂度
不高于n^2)-因此,假设此答案中的每个O(x)表示“大θ”,即渐近上/下边界,这样
f(n)在O(g(n))中表示k1*g(n)O(C)>O(n^2/(logn)^C*(loglogn)^3/2)(请注意,这只表示比纯n^2有微小的改进)
也就是说,我对A的建议如下:
a) 由于矩阵相对于对角线是对称的,假设我们只分析右上三角形加对角线
b) 假设对于n,集合中有任何数字x=
c) 计算y=int(sqrt(n))-行ry的每个对角线值
必须进行检查
c')n*(n+1)/2-n-int(sqrt(n))元素需要在“常规”方法中处理(添加到集合中)
d) 现在,由于我们排除了所有容易预测的值,我们进入了主循环:
对于(行r(r-1)*n到目前为止都保证是唯一的,因此假设我们不必维护唯一的数字集,则无需对它们进行处理!;
由于行的集合用于数字(r^2;r*n),因此行r中范围((r-1)n,rn)内的所有数字都在范围内
现在,由于第r行中的实际数字集是a_n=r,2*r,3*r…nr,显而易见的问题是
一个“边界”整数yr,使得y*r>(r-1)*n,因为这意味着我们有n-y保证唯一性。
注意:如果我们发现((r-1)*n)/r的精确值是一个整数,我们可以安全地假设y=((r-1)*n)/r+1(为什么?),
这个整数不是唯一的。
正因为如此,每一行中都有max(n-r,ceil(n/r))保证的唯一性(为什么?);我们在O(1)中得到每一行的唯一性
e) 最棘手的部分:我们得到了一些大于r*r的数,但明显小于(r-1)n;
即“硬范围”[rr,(r-1)*n),其中数字可以是唯一的,也可以不是唯一的;
我们最多可以有i_r=max(0,n-r-floor(n/r))个数字来检查这个范围(为什么?)
即使是简单地检查这个范围内的每个数字也明显比O(n)快(为什么?-地板(n/r)因子相对于n增长!)
我们已经得到了比O(n^2)更好的结果——我们有sum(i_r)迭代,对于r=2..n(第一行不是op),所以这实际上等于
r=2..n的和(max(0,n-r-floor(n/r))-这里我不提供精确的复杂性类结果,因为它不是一个很好的数字,
让我们试着更进一步
f) 弹射器怎么样
g) 对于奇数行,我们不能做更多的事情(因为在许多事情中,这需要我们解决一些与素数相关的问题)
这些问题,已经在评论中提到了,对于世界上最好的Matematicators来说还没有得到解决),但我们仍然可以
请自便吧
把r除以2。每一个的数字我都相信有一个比O(n²)更好的解决方案。我没有找到它,但我相信我走的是正确的道路,只有几点数学见解
这是我正在开发的算法:
public static int numberOfDistinctResults(int n) {
if (n == 1) {
return 1;
}
// runs a prime-number sieve in O(n log log n)
Factorization.initialize(n);
int total = 1;
for (int i = 2; i <= n; i++) {
total += i;
// divs[i] == 0 iff i is prime, or the lowest prime that divides i
if (Factorization.divs[i] == 0) {
// i is prime; for all j<=i, j*i is brand new; nothing to substract
} else {
// i is non-prime; discard already-seen decompositions
total -= magic(n); // <--- this part needs work
}
}
return total;
}
好吧,如果你计算出i*j
,你当然不需要计算出j*i
——它仍然是O(n^2)
但这是工作的一半。我认为这是不用钻研数论就可以做到的最好的方法;在Java或任何其他语言中,我看不到更好的方法。基于此,我认为这应该结束。这不是一个关于编程的问题,而是一个数学问题,它肯定很有趣。如果有π(x)的公式,素数计数函数,它可以在O(1)中求解;-)@user1990169即使在3x3示例中,我们也有8,它介于n和n^2之间,但既不是素数,也不是解的一部分。@tucuxi:在OP的示例中,n
是3。所以他的方法是O(n^2)。正如您所指出的,筛选是O(n log log n),其中n
是运行它所针对的项目数。在这种情况下,您必须对9个项目运行它。因此筛选是O(n^2 log(n^2))),其中n==3。如果你需要迭代n²,那么显然没有办法低于n²。我一直在试图找到一个递增的答案,但oeis.org/A108407很难破解。天哪。如果有人真的解决了这个问题,他/她最好写一篇论文,而不是一个SO答案。这个问题与计算素数不同,它与counti完全相同n^2减去n和n^2之间的素数,因为n和n^2之间的每一个数都必须被2和n之间的一个数整除,或者它必须是素数。@MarkRansom没有标记,这是错误的。我实际上做了一次失败的尝试,基于“减去n和n^2之间的素数可整除的事物”。有一个简单的计数r示例:在n=3
的情况下,8
不在乘法表中,也不能被3
和9
之间的任何素数整除。另一个说服您的示例是:以n=9
为例,那么75
也不能被9
之间的任何素数整除
f(1) = 1 ( prev + 1 = 1 - 0)
f(2) = 3 ( prev + 2 = 2 - 0)
f(3) = 6 ( prev + 3 = 3 - 0)
f(4) = 9 ( prev + 3 = 4 - 1)
4 = 2^2; available = 2·3
f(5) = 14 ( prev + 5 = 5 - 0)
f(6) = 18 ( prev + 4 = 6 - 2)
6 = 2·3; available = 2^2·3·5
f(7) = 25 ( prev + 7 = 7 - 0)
f(8) = 30 ( prev + 5 = 8 - 3)
8 = 2^3; available = 2^2·3·5·7
f(9) = 36 ( prev + 6 = 9 - 3)
9 = 3^2; available = 2^3·3·5·7
f(10) = 42 ( prev + 6 = 10 - 4)
10 = 2·5; available = 2^3·3^2·5·7
f(11) = 53 ( prev + 11 = 11 - 0)
f(12) = 59 ( prev + 6 = 12 - 6)
12 = 2^2·3; available = 2^3·3^2·5·7·11
f(13) = 72 ( prev + 13 = 13 - 0)
f(14) = 80 ( prev + 8 = 14 - 6)
14 = 2·7; available = 2^3·3^2·5·7·11·13
f(15) = 89 ( prev + 9 = 15 - 6)
15 = 3·5; available = 2^3·3^2·5·7·11·13
f(16) = 97 ( prev + 8 = 16 - 8)
16 = 2^4; available = 2^3·3^2·5·7·11·13
f(17) = 114 ( prev + 17 = 17 - 0)
f(18) = 123 ( prev + 9 = 18 - 9)
18 = 2·3^2; available = 2^4·3^2·5·7·11·13·17
f(19) = 142 ( prev + 19 = 19 - 0)
f(20) = 152 ( prev + 10 = 20 - 10)
20 = 2^2·5; available = 2^4·3^2·5·7·11·13·17·19
f(21) = 164 ( prev + 12 = 21 - 9)
21 = 3·7; available = 2^4·3^2·5·7·11·13·17·19
f(22) = 176 ( prev + 12 = 22 - 10)
22 = 2·11; available = 2^4·3^2·5·7·11·13·17·19
f(23) = 199 ( prev + 23 = 23 - 0)
f(24) = 209 ( prev + 10 = 24 - 14)
24 = 2^3·3; available = 2^4·3^2·5·7·11·13·17·19·23
f(25) = 225 ( prev + 16 = 25 - 9)
25 = 5^2; available = 2^4·3^2·5·7·11·13·17·19·23
f(26) = 239 ( prev + 14 = 26 - 12)
26 = 2·13; available = 2^4·3^2·5^2·7·11·13·17·19·23
f(27) = 254 ( prev + 15 = 27 - 12)
27 = 3^3; available = 2^4·3^2·5^2·7·11·13·17·19·23
f(28) = 267 ( prev + 13 = 28 - 15)
28 = 2^2·7; available = 2^4·3^3·5^2·7·11·13·17·19·23
f(29) = 296 ( prev + 29 = 29 - 0)
f(30) = 308 ( prev + 12 = 30 - 18)
30 = 2·3·5; available = 2^4·3^3·5^2·7·11·13·17·19·23·29
f(31) = 339 ( prev + 31 = 31 - 0)
f(32) = 354 ( prev + 15 = 32 - 17)
32 = 2^5; available = 2^4·3^3·5^2·7·11·13·17·19·23·29·31
f(33) = 372 ( prev + 18 = 33 - 15)
33 = 3·11; available = 2^5·3^3·5^2·7·11·13·17·19·23·29·31
f(34) = 390 ( prev + 18 = 34 - 16)
34 = 2·17; available = 2^5·3^3·5^2·7·11·13·17·19·23·29·31
f(35) = 410 ( prev + 20 = 35 - 15)
35 = 5·7; available = 2^5·3^3·5^2·7·11·13·17·19·23·29·31
f(36) = 423 ( prev + 13 = 36 - 23)
36 = 2^2·3^2; available = 2^5·3^3·5^2·7·11·13·17·19·23·29·31
f(37) = 460 ( prev + 37 = 37 - 0)
f(38) = 480 ( prev + 20 = 38 - 18)
38 = 2·19; available = 2^5·3^3·5^2·7·11·13·17·19·23·29·31·37
f(39) = 501 ( prev + 21 = 39 - 18)
39 = 3·13; available = 2^5·3^3·5^2·7·11·13·17·19·23·29·31·37