Greatest Common Divisor Traversal - Union Find [JS]

Description 

Solution: Union Find

Key point: For all pairs of indices to be traversable, all nodes must be connected.
Find the prime factors of each number (there are about log(n) prime factors per number).
Keep a map of factors to any number with that prime factor so far: {prime factor: index, prime factor: index, ...}
Note: We don't need to connect with every single number with that prime factor since connecting to just one number means we will also connect with all other numbers that are already connected.
Use union find to connect numbers that share the same prime factors.

Time Complexity: O(n log(n)) 701ms
Space Complexity: O(n) 72.8MB

var canTraverseAllPairs = function(nums) {
  let n = nums.length, map = new Map(), uf = new UnionFind(n);
  for (let i = 0; i < n; i++) {
    let primeFactors = getPrimeFactors(nums[i]);
    for (let factor of primeFactors) {
      if (map.has(factor)) uf.union(i, map.get(factor));
      else map.set(factor, i);
    }
  }
  return uf.size === 1;
};

function getPrimeFactors(n) {
  let res = new Set();
  for (let x = 2; (x * x) <= n; x++) {
    // loop while n is divisible by x
    while (n % x === 0) {
      res.add(x);
      n /= x;
    }
  }
  if (n > 1) res.add(n);
  return res;
}

class UnionFind {
  constructor(size) {
    this.size = size;
    this.root = Array(size);
    this.rank = Array(size);
    for (let i = 0; i < size; i++) {
      this.root[i] = i;
      this.rank[i] = 1;
    }
  }
  find(x) {
    if (this.root[x] === x) return x;
    return this.root[x] = this.find(this.root[x]);
  }
  union(x, y) {
    let rootX = this.find(x), rootY = this.find(y);
    if (rootX === rootY) return false;
    if (this.rank[rootX] < this.rank[rootY]) {
      this.root[rootX] = rootY;
    } else if (this.rank[rootX] > this.rank[rootY]) {
      this.root[rootY] = rootX;
    } else {
      this.root[rootY] = rootX;
      this.rank[rootX]++;
    }
    this.size--;
    return true;
  }
  isConnected(x, y) {
    return this.find(x) === this.find(y);
  }
}

Comments

Popular posts from this blog

Maximum Value of an Ordered Triplet II - Two Solutions [JS]

Maximum Sum of Distinct Subarrays With Length K - Sliding Window w/ Two Pointers & Set [JS]

Sum of Prefix Scores of Strings - Trie [JS]

Maximum Count of Positive Integer and Negative Integer - Binary Search [JS]

Count Subarrays With Median K - Count Left & Right Balance [JS]