Open In App

Chinese Remainder Theorem in Python

Last Updated : 16 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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:

  • Initialize x to 1 as the starting point for the search.
  • Iterate through each congruence and check if x satisfies the congruence by checking if x mod nums[j]=rems[j].
  • If x satisfies all congruences, then we have found the solution x and return it.
  • If x does not satisfy all congruences, increment x by 1 and repeat the process.

Below is the implementation of the above approach:

Python
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:

  • Compute the product of all numbers in the num[] array. Let’s call this product prod.
  • For each pair of num[i] and rem[i], compute the product of all numbers in num[] except num[i], denoted as prod_i.
  • Use the Extended Euclidean Algorithm to find the modular inverse of prod_i modulo num[i]. Let’s call this inverse inv_i.
  • Calculate the solution x using the formula:
gfg

Formula


Below is the implementation of the above approach:

Python
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)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads