Skip to main content

Command Palette

Search for a command to run...

Solving Leetcode Interviews in Seconds with AI: Greatest Common Divisor Traversal

Updated
4 min read

Introduction

In this blog post, we will explore how to solve the LeetCode problem "2709" using AI. LeetCode is a popular platform for preparing for coding interviews, and with the help of AI tools like Chatmagic, we can generate solutions quickly and efficiently - helping you pass the interviews and get the job offer without having to study for months.

Problem Statement

You are given a 0-indexed integer array nums, and you are allowed to traverse between its indices. You can traverse between index i and index j, i != j, if and only if gcd(nums[i], nums[j]) > 1, where gcd is the greatest common divisor. Your task is to determine if for every pair of indices i and j in nums, where i < j, there exists a sequence of traversals that can take us from i to j. Return true if it is possible to traverse between all such pairs of indices, or false otherwise. Example 1: Input: nums = [2,3,6] Output: true Explanation: In this example, there are 3 possible pairs of indices: (0, 1), (0, 2), and (1, 2). To go from index 0 to index 1, we can use the sequence of traversals 0 -> 2 -> 1, where we move from index 0 to index 2 because gcd(nums[0], nums[2]) = gcd(2, 6) = 2 > 1, and then move from index 2 to index 1 because gcd(nums[2], nums[1]) = gcd(6, 3) = 3 > 1. To go from index 0 to index 2, we can just go directly because gcd(nums[0], nums[2]) = gcd(2, 6) = 2 > 1. Likewise, to go from index 1 to index 2, we can just go directly because gcd(nums[1], nums[2]) = gcd(3, 6) = 3 > 1. Example 2: Input: nums = [3,9,5] Output: false Explanation: No sequence of traversals can take us from index 0 to index 2 in this example. So, we return false. Example 3: Input: nums = [4,3,12,8] Output: true Explanation: There are 6 possible pairs of indices to traverse between: (0, 1), (0, 2), (0, 3), (1, 2), (1, 3), and (2, 3). A valid sequence of traversals exists for each pair, so we return true. Constraints: 1 <= nums.length <= 105 1 <= nums[i] <= 105

Explanation

Here's a solution to the problem, along with a breakdown of the approach and complexity:

  • Core Idea: Use the concept of connected components. If all indices belong to a single connected component based on the gcd > 1 traversal rule, then all pairs of indices are reachable. Union-Find data structure is the perfect tool to efficiently detect connected components.

  • Prime Factorization Optimization: The GCD calculation can be sped up by considering the prime factors of each number. If two numbers share a prime factor, their GCD will be greater than 1. We can precompute prime factors to avoid redundant GCD calculations.

  • Union-Find: A Union-Find data structure allows us to efficiently merge the connected components identified by shared prime factors. After processing all numbers, we check if all indices are in the same connected component by checking if they have the same root.

  • Complexity:

    • Runtime: O(N * sqrt(M) + N * α(N)), where N is the length of nums, M is the maximum value in nums, and α(N) is the inverse Ackermann function which grows very slowly and can be considered O(1) for practical purposes. O(N * sqrt(M)) is for prime factorization for each number. O(N * α(N)) is the complexity of the union-find algorithm.
    • Storage: O(N + M), N for the parent array in Union-Find and M for storing prime factors.

Code

    import math

class UnionFind:
    def __init__(self, n):
        self.parent = list(range(n))
        self.rank = [0] * n

    def find(self, x):
        if self.parent[x] != x:
            self.parent[x] = self.find(self.parent[x])  # Path compression
        return self.parent[x]

    def union(self, x, y):
        root_x = self.find(x)
        root_y = self.find(y)
        if root_x != root_y:
            if self.rank[root_x] < self.rank[root_y]:
                self.parent[root_x] = root_y
            elif self.rank[root_x] > self.rank[root_y]:
                self.parent[root_y] = root_x
            else:
                self.parent[root_y] = root_x
                self.rank[root_x] += 1


def largest_prime_factor(n):
    i = 2
    factors = set()
    while i * i <= n:
        if n % i:
            i += 1
        else:
            factors.add(i)
            while n % i == 0:
                n //= i
    if n > 1:
        factors.add(n)
    return factors


def canTraverseAllPairs(nums):
    n = len(nums)
    if n == 1:
        return True

    uf = UnionFind(n)
    prime_index = {}  # prime: index in nums

    for i in range(n):
        factors = largest_prime_factor(nums[i])
        if not factors:
            if nums[i] > 1:
                return False

        for prime in factors:
            if prime in prime_index:
                uf.union(i, prime_index[prime])
            else:
                prime_index[prime] = i

    # Check if all elements are in the same connected component
    root = uf.find(0)
    for i in range(1, n):
        if uf.find(i) != root:
            return False

    return True

More from this blog

C

Chatmagic blog

2894 posts