Open In App

Chinese Remainder Theorem in Python

Consider two arrays "num[0..k-1]" and "rem[0..k-1]", where every pair of numbers in num is coprime (i.e., the greatest common divisor (gcd) of every pair is 1). The goal is to find the minimum positive number "x" such that:

x % num[0] = rem[0]

x % num[1] = rem[1]

.....

x % num[k-1] = rem[k-1]

In simpler terms, given "k" numbers that are pairwise coprime and their corresponding remainders when an unknown number "x" is divided by them, we aim to determine the smallest possible value of "x" that satisfies these congruences.

Examples:

Input:
num[] = {3, 4, 5}
rem[] = {2, 3, 1}
Output: 11
Explanation: 11 is the smallest number such that:
(1) When we divide it by 3, we get remainder 2.
(2) When we divide it by 4, we get remainder 3.
(3) When we divide it by 5, we get remainder 1.

Input:
num[] = {2, 3, 7}
rem[] = {1, 2, 5}
Output: 17
Explanation: 17 is the smallest number such that:
(1) When we divide it by 2, we get remainder 1.
(2) When we divide it by 3, we get remainder 2.
(3) When we divide it by 7, we get remainder 5.

Chinese Remainder Theorem:

The Chinese Remainder Theorem states that for positive integers num[0], num[1], …, num[k-1] that are pairwise coprime, and any given sequence of integers rem[0], rem[1], …, rem[k-1], there exists an integer x that solves the system of simultaneous congruences as described earlier.

Chinese Remainder Theorem in Python Using Naive Approach:

Fetching the mystery number x is fairly easy if we start with 1 and keep on seeing if numbers being divided by the elements in num[] equals the corresponding remainders in rem[]. Upon locating a variable like x, the algorithm stops, and the solution is given. Yet, it can lead to inefficiency in cases with higher than average num[].

Steps-by-step approach for Chinese Remainder Theorem in Python:

Below is the implementation of the above approach:

def find_min_x(nums, rems):
   # Initialize result
    x = 1 

    while True:
        # Check if remainder of x % nums[j] is rem[j] for all j from 0 to k-1
        for j in range(len(nums)):
            if x % nums[j] != rems[j]:
                break

        # If all remainders matched, we found x
        if j == len(nums) - 1:
            return x

        # Else, try the next number
        x += 1

    return x

# Example Usage
nums = [3, 4, 5]
rems = [2, 3, 1]
print(find_min_x(nums, rems))

Output
11

Time Complexity: O(M), where M is the product of all elements in the nums array.
Auxiliary Space: O(1)

Chinese Remainder Theorem in Python Using Extended Euclidean Algorithm:

The Extended Euclidean Algorithm is used to find the greatest common divisor (GCD) of two integers a and b, as well as the coefficients x and y such that ax+by=gcd(a,b)

Steps-by-step algorithm:

gfg

Formula


Below is the implementation of the above approach:

def gcd_extended(a, b):
    if a == 0:
        return b, 0, 1
    gcd, x1, y1 = gcd_extended(b % a, a)
    x = y1 - (b // a) * x1
    y = x1
    return gcd, x, y

def find_min_x(num, rem):
    prod = 1
    for n in num:
        prod *= n

    result = 0
    for i in range(len(num)):
        prod_i = prod // num[i]
        _, inv_i, _ = gcd_extended(prod_i, num[i])
        result += rem[i] * prod_i * inv_i

    return result % prod

# Example Usage
num1 = [5, 7]
rem1 = [1, 3]
print("x is", find_min_x(num1, rem1)) 

num2 = [3, 4, 5]
rem2 = [2, 3, 1]
print("x is", find_min_x(num2, rem2))  

Output
('x is', 31)
('x is', 11)

Time Complexity : O(k log(prod)) where k is the number of elements in the array and prod is the product of the elements in the array.
Auxiliary Space : O(1)

Article Tags :
DSA