Problem Statement

Given two numbers N and M, find the Nth root of M. The Nth root of a number M is defined as a number X such that when X is raised to the power of N, it equals M. If the Nth root is not an integer, return -1.

Examples

Example 1:

Input: N = 3, M = 27
Output: 3

Explanation: The cube root of 27 is equal to 3.
Example 2:

Input: N = 4, M = 69
Output: -1

Explanation: The 4th root of 69 does not exist. So, the answer is -1.
Example 3:

Input: N = 4, M = 81
Output: 3

Explanation: Because 3 * 3 * 3 * 3 = 81.

Constraints:

  • 1 ≤ N ≤ 30
  • 1 ≤ M ≤ 10^9

Different Approaches

1️⃣ Brute Force Approach

Intuition:

Perform a simple linear search in range[1, n]. Calculate the value of x raised to the power n for every number in the range. If it is equal to given number then x is the nth root of the number. If no such number (x) exists, return -1 as an answer.

Code:

#include <bits/stdc++.h>
using namespace std;

class Solution {
private:
    /* Function to calculate power using
    exponentiation by squaring method*/
    long long func(int b, int exp) {
        long long ans = 1;
        long long base = b;
        
        // Exponentiation by squaring method
        while (exp > 0) {
            if (exp % 2) {
                exp--;
                ans = ans * base;
            } else {
                exp /= 2;
                base = base * base;
            }
        }
        return ans;
    }
public:
    /* Function to find the nth root
    of m using linear search*/
    int NthRoot(int N, int M) {
        // Linear search on the answer space
        for (int i = 1; i <= M; i++) {
            long long val = func(i, N);
            
            /* Check if the computed
            value is equal to M */
            if (val == M * 1ll) {
                // Return the root value
                return i; 
            } else if (val > M * 1ll) {
                break;
            }
        }
        // Return -1 if no root found
        return -1; 
    }
};

int main() {
    int n = 3, m = 27;
    
    // Create an object of the Solution class
    Solution sol;
    
    int ans = sol.NthRoot(n, m);
    
    // Print the result
    cout << "The answer is: " << ans << "\n";
    
    return 0;
}

Complexity Analysis:

  • Time Complexity: O(N), where N is the given number. Since we are using linear search, we traverse the entire answer space.
  • Space Complexity: As no additional space is used, so the Space Complexity is O(1).

2️⃣ Binary Search

The idea here is to use binary search to optimize the solution. Although the traditional application of binary search involves a sorted array, upon clear observation, one can notice that the search space for the answer here ranges from 1 to n, which inherently forms a sorted sequence . So, binary search can be applied.

Code:

#include <bits/stdc++.h>
using namespace std;

class Solution {
private:
    /* Helper function to check the power of mid 
    with respect to m Returns: 1 - if mid^n == m,
    0 - if mid^n < m and 2 - if mid^n > m */
    int func(int mid, int n, int m) {
        long long ans = 1;
        for (int i = 1; i <= n; i++) {
            ans *= mid;
            // This is to handle overflow in multiplication
            if (ans > m) return 2;
        }
        if (ans == m) return 1;
        return 0;
    }
public:
    /* Function to find the nth root
    root of m using binary search*/
    int NthRoot(int N, int M) {
        // Binary search on the answer space
        int low = 1, high = M;
        
        while (low <= high) {
            int mid = (low + high) / 2;
            int midN = func(mid, N, M);
            if (midN == 1) {
                
                // Return mid if mid^N== M
                return mid;
            } 
            else if (midN == 0) {
                // Move to the right half if mid^N < M
                low = mid + 1;
            } 
            else {
                // Move to the left half if mid^N > M
                high = mid - 1;
            }
        }
        // Return -1 if no nth root found
        return -1;
    }
};

int main() {
    int n = 3, m = 27;
    
    // Create an object of the Solution class
    Solution sol;
    
    int ans = sol.NthRoot(n, m);
    
    // Print the result
    cout << "The answer is: " << ans << "\n";
    
    return 0;
}

Complexity Analysis:

  • Time Complexity: O(logN), N is the given number. We are basically using binary search to find the minimum.
  • Space Complexity: As no additional space is used, so the Space Complexity is O(1).