如何计算具有一些约束的数组中每个索引的GCD

时间:2016-11-19 13:28:10

标签: arrays algorithm greatest-common-divisor

鉴于 1 - 索引数组 A 的大小 N ,任何距离 此 i 2 指数由 | i-j | 给出。现在,根据这些信息,我需要找到每个指数 i (1≤i≤N),索引 j ,这样< strong>1≤j≤N, i≠j GCD(A [i],A [j])> 1

如果索引 i 有多个这样的候选者,则必须找到索引 j ,以便 i j 很少。如果仍有多个候选者,请打印满足上述约束的最小 j

  

实施例:   数组(A) 2 3 4 9 17

输出:3 4 1 2 -1

注意:数组大小可以大到2 * 10 ^ 5。 每个数组元素的最大值可以是2 * 10 ^ 5,最小值是1。

我应该能够在最多1秒内计算出来。

这是我的代码,但超出了时间限制。有没有办法优化它。

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class GCD {


public static void main(String[] args) throws IOException {

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    int n = Integer.parseInt(br.readLine().trim());
    int[] a = new int[n+1];
    StringBuilder sb =new StringBuilder("");
    String[] array = br.readLine().trim().split(" ");

    for(int i=1; i<=n; i++){
        a[i] = Integer.parseInt(array[i-1]);
    }

    int c,d;
l1: for(int i=1; i<=n; i++){
        c = i-1;
        d = i+1;
        while((c>0||d<=n)){
            if(c>0){
                if(GCD(a[i],a[c])>1){
                    sb.append(c+" ");
                    continue l1;
                }
            }
            if(d<=n){   
                if(GCD(a[i],a[d])>1){
                    sb.append(d+" ");
                    continue l1;
                }   
            }
            c--;
            d++;
        }

         sb.append("-1 ");
    }
    System.out.println(sb);
}


    static long GCD(int a, int b){
        if(b==0)
           return a;
        return GCD(b, a%b);
    }

}

2 个答案:

答案 0 :(得分:0)

要在1秒内运行,您的算法应为θ(N)或θ(N * log(N)),N <2 * 10 ^ 5。一种方法是:

  1. 让我们在数组的1次迭代中找到除1之外的所有因子。复杂度=θ(N)*θ(GCD)=θ(N * log(N))
  2. 创建一个hashmap,key =我们刚找到的因子,value =排序输入元素索引的数组,它们的因子是。 (哈希映射中的数组按顺序排列,因此不需要显式排序。因子数&lt;θ(log(N)))复杂度=θ(N * log(N))
  3. 现在我们迭代元素并在每个元素中迭代因子,并且对于每个因子,我们从哈希映射中找到使用二分搜索在最近的索引中存在该因子的情况。我们为每个元素的所有因子选择最接近的值,并将其作为答案。复杂度=θ(N * log(N)* log(log(N)))。

答案 1 :(得分:0)

你知道问题可以在一秒钟内解决。你知道这个数组可以有200,000个元素。将200,000个元素与200,000个元素进行比较需要进行400亿次比较。如果你很幸运,你的计算机每秒可以完成30亿次操作。您会发现,将200,000个元素与200,000个元素进行比较是行不通的。 (这将发生在所有数组元素都等于1的简单情况下)。因此,优化您的代码无济于事。

因此,请将您的思维从提出问题的方式移开。它要求找到j使得gcd(a [i],a [j])!= 1.它真正意味着找到j使得[j]具有与[i]共同的素因子。并且j需要是最大的j&lt;我或最小的j>一世。

数字很小,不到200,000。因此,您可以非常快速地找到a [i]的所有不同素因子。

首先你创建一个数组“index”:对于每个素数p <= 200,000,index [p]是你检查过的具有素数因子p的最后一个数组元素a [j]的索引j,如果你没找到,则为-1。您还可以创建一个数组“解决方案”:对于您检查的每个i,它包含到目前为止最接近的数字或-1。

遍历数组i = 1到n:对于每个a [i],找到所有素数因子。对于每个因子p:如果j = index [p]&gt; 0然后a [j]也可以被p整除,所以gcd(a [i],a [j])&gt; 1.做到这一点,你得到最大的j&lt;我用gcd(a [i],a [j])&gt; 1.当您找到素数因子时,还要更新数组索引。

但是如果你发现a [i]和[j]有一个共同因子,那么你为j存储的解决方案可能是错误的,因为它只考虑小于j的索引,所以也更新解决方案。伪代码:

Create array "index" filled with -1.
Create array "solution" filled with -1.

for all i
    for all prime factors p of a [i]
        let j = index [p]
        index [p] = j
        if j >= 0
            if solution [i] = -1
                solution [i] = j
            else if j > solution [i]
                solution [i] = j

            if solution [j] = -1
                solution [j] = i
            else if solution [j] < j && i-j < j - solution [j]
                solution [j] = i

print solution

你可以看到,具有公共因子的数组元素离开多远并不重要。执行时间是素数因子的数量的非常小的倍数加上找到因子的时间,如果所有元素都是大素数,则这是最差的。所以你需要做的就是找到任何数字的所有因素&lt; 200,000,比如说3-4微秒。应该很容易。在开始之前,您可以创建一个最多500的素数表。