【问题标题】:Finding number of pairs, product of whose indices is divisible by another number X查找对数,其索引的乘积可被另一个数 X 整除
【发布时间】:2021-12-08 23:29:18
【问题描述】:

给定一个数组和某个值 X,找出满足 i < ja[i] = a[j](i * j) % X == 0 的对数

Array size <= 10^5

我正在考虑这个问题一段时间,但只能提出蛮力解决方案(通过检查所有对),这显然会超时[O(N^2) time complexity]

有更好的方法吗?

【问题讨论】:

  • 这当然取决于具体数字,但对于数组大小 N 的较大值,首先完全分解 X 然后遍历 X 的除数 d d = 1。这不是我的想法,请对待它持怀疑态度。
  • ij 是什么?
  • 在我的答案中添加了针对蛮力测试的代码。

标签: algorithm sorting math data-structures


【解决方案1】:

首先,在我们迭代时为每个不同的A[i] 存储单独的搜索结构。

i * j = k * X
i = k * X / j

X / j 成为分数。由于i 是一个整数,所以k 的格式为m * least_common_multiple(X, j) / X, where m is natural

示例 1:j = 20X = 60

lcm(60, 20) = 60
matching `i`s would be of the form:
(m * 60 / 60) * 60 / 20
=> m * q, where q = 3

示例 2:j = 6X = 2

lcm(2, 6) = 6
matching `i`s would be of the form:
(m * 6 / 2) * 2 / 6
=> m * q, where q = 1

接下来,我将考虑如何有效地查询任意自然数的排序列表中数字的倍数。一种方法是散列我们添加到A[i] 的搜索结构中的每个i 的除数频率。但首先将i 视为j,并将哈希映射中已存在的除数q 添加到结果中。

最后带有蛮力测试的 JavaScript 代码:

function gcd(a, b){
  return b ? gcd(b, a % b) : a;
}


function getQ(X, j){
  return X / gcd(X, j);
}


function addDivisors(n, map){
  let m = 1;
    
  while (m*m <= n){
    if (n % m == 0){
      map[m] = -~map[m];
      
      const l = n / m;
      
      if (l != m)
        map[l] = -~map[l];
    }
    
    m += 1;
  }
}


function f(A, X){
  const Ais = {};
  let result = 0;
  
  for (let j=1; j<A.length; j++){
    if (A[j] == A[0])
      result += 1;

    // Search
    if (Ais.hasOwnProperty(A[j])){
      const q = getQ(X, j);

      result += Ais[A[j]][q] || 0;
    
    // Initialise this value's
    // search structure
    } else {
      Ais[A[j]] = {};
    }
    
    // Add divisors for j
    addDivisors(j, Ais[A[j]]);
  }
  
  return result;
}


function bruteForce(A, X){
  let result = 0;
  
  for (let j=1; j<A.length; j++){
    for (let i=0; i<j; i++){
      if (A[i] == A[j] && (i*j % X) == 0)
        result += 1;
    }
  }
  
  return result;
}


var numTests = 1000;
var n = 100;
var m = 50;
var x = 100;

for (let i=0; i<numTests; i++){
  const A = [];

  for (let j=0; j<n; j++)
    A.push(Math.ceil(Math.random() * m));
    
  const X = Math.ceil(Math.random() * x);
  
  const _brute = bruteForce(A, X);
  const _f = f(A, X);

  if (_brute != _f){
    console.log("Mismatch!");
    console.log(X, JSON.stringify(A));
    console.log(_brute, _f);
    break;
  }
}

console.log("Done testing.")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-04-18
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多