Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
Bit Manipulation and Binary Search are some of the few topics that students generally neglect while focusing on other important topics of Data Structures and Algorithms. However, when applied to questions, these topics enhance the time and space complexity of the problem and make the solution relatively easy and understandable.
Today we will discuss one such significant problem, Divide Two Integers that can easily be solved using Bitwise operators and binary search, and see how brute force may sometimes become inefficient and generate errors like Time Limit Exceed.
Problem Statement:
You have been given two integers, a dividend, and a divisor. The problem states that you have to divide two integers, the dividend, and divisor without using multiplication, division, or mod operator. Also, the function must return the floor value of the quotient.
Assumption→ We assume that we are dealing with an environment that can store integers only within the 32-bit signed integer range, i.e., [- 231, 231 - 1].
So assume that your function returns 231 - 1 when the division result overflows.
// C++ program to divide two numbers using brute force. #include <iostream> #include <climits> using namespace std;
// Function to find the quotient. int divide(int dividend, int divisor) { if (divisor == 1) return dividend;
if (dividend == INT_MIN) { dividend++; }
// Initialising the sign as 1 and quotient as 0. int sign = -1, quotient = 0;
// If one of the dividends or divisor is negative, the sign becomes negative. if ((dividend < 0 && divisor < 0) || (dividend >= 0 && divisor >= 0)) sign = 1;
// Taking positive values of both dividend and divisor. dividend = abs(dividend); divisor = abs(divisor);
// Calculating the value of quotient. while (dividend >= divisor) { dividend -= divisor; quotient++; }
// Returning the answer by multiplying the sign with the quotient. return quotient * sign; } int main() { int dividend, divisor;
// Taking user input. cout << "Enter the dividend and divisor: "; cin >> dividend >> divisor;
// Calling the function and printing the answer. cout << "The quotient is " << divide(dividend, divisor);
return 0; }
You can also try this code with Online C++ Compiler
while (dividend >= divisor) { dividend -= divisor; quotient++; }
return quotient * sign; }
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter the dividend and divisor: "); int dividend = scanner.nextInt(); int divisor = scanner.nextInt();
System.out.println("The quotient is " + divide(dividend, divisor)); } }
You can also try this code with Online Java Compiler
while (dividend >= divisor) { dividend -= divisor; quotient++; }
return quotient * sign; }
static void Main(string[] args) { Console.Write("Enter the dividend and divisor: "); string[] inputs = Console.ReadLine().Split(' '); int dividend = int.Parse(inputs[0]); int divisor = int.Parse(inputs[1]);
Console.WriteLine("The quotient is " + divide(dividend, divisor)); } }
Input:
Enter the dividend and divisor: -14 -2
Output:
The quotient is 7.
Time Complexity
The time complexity of this approach is O(abs(M - N) / N), where M is the dividend and N is the divisor.
The time complexity is linear since we traverse the numbers between M - N and divide them by N.
Space Complexity
The space complexity of this approach is O(1).
Since we are not using any extra space to store the numbers, the space complexity of this solution is constant, i.e. O(1).
NOTE→ Though this approach is correct, it will not be accepted as the problem’s solution because of the constraints. The IDE will always throw a Time Limit Exceed on test cases where the dividend is too large, and the divisor is too small.
int divide(int dividend, int divisor) { unsigned long long int lo = 0; unsigned long long int hi = abs(dividend);
if (dividend == INT_MIN) { if (divisor == -1) return INT_MAX; else if (divisor == 1) return INT_MIN; }
int quotient = 0;
while (lo <= hi) { unsigned long long int mid = (lo + hi) / 2; if (abs(divisor) * mid <= abs(dividend)) { quotient = mid; lo = mid + 1; } else { hi = mid - 1; } }
int main() { int dividend, divisor; printf("Enter the dividend and divisor: "); scanf("%d %d", ÷nd, &divisor); printf("The quotient is %d", divide(dividend, divisor)); return 0; }
// C++ program to divide two numbers using binary search. #include <iostream> #include <climits> using namespace std;
// Function to find the quotient. int divide(int dividend, int divisor) { unsigned long long int lo = 0; unsigned long long int hi = abs(dividend);
// Checking the condition for overflow. if (dividend == INT_MIN) { if (divisor == -1) { return INT_MAX; } else if (divisor == 1) { return INT_MIN; } }
int quotient = 0;
// Performing binary search on the given range of numbers. while (lo <= hi) { unsigned long long int mid = (lo + hi) / 2; if (abs(divisor) * mid <= abs(dividend)) { quotient = mid; lo = mid + 1; } else { hi = mid - 1; } }
// Checking the parity of the answer and returning it accordingly. return ((dividend < 0 && divisor < 0) || (dividend >= 0 && divisor >= 0) ? quotient : -quotient); } int main() { int dividend, divisor;
// Taking user input. cout << "Enter the dividend and divisor: "; cin >> dividend >> divisor;
// Calling the function and printing the answer. cout << "The quotient is " << divide(dividend, divisor);
return 0; }
You can also try this code with Online C++ Compiler
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter the dividend and divisor: "); int dividend = scanner.nextInt(); int divisor = scanner.nextInt(); System.out.println("The quotient is " + divide(dividend, divisor)); } }
You can also try this code with Online Java Compiler
static void Main(string[] args) { Console.Write("Enter the dividend and divisor: "); string[] inputs = Console.ReadLine().Split(' '); int dividend = int.Parse(inputs[0]); int divisor = int.Parse(inputs[1]);
Console.WriteLine("The quotient is " + Divide(dividend, divisor)); } }
Input:
Enter the dividend and divisor: 10 3
Output:
The quotient is 3.
Time Complexity
The time complexity of this approach is O(log N), where N is the DIVIDEND.
Since we have used binary search to perform the division and the time complexity of Binary Search is O(log N), where N is the number of elements in the array, so the time complexity of the solution is O(log N), where N is the DIVIDEND.
Space Complexity
The space complexity of this approach is O(1).
Since we are not using any extra space to store the numbers, the space complexity of this solution is constant, i.e., O(1).
Bit Manipulation
Algorithm
We find the greatest power of 2, which, when multiplied by the quotient, gives an answer that is just smaller than the dividend.
After finding this power, we add it to our answer.
We reduce the dividend by the divisor multiplied by this power of 2 found.
Now, we perform the above operation once again with the reduced dividend.
Let’s consider a simple example to be more clear:
Suppose,
DIVIDEND = 10
DIVISOR = 3
Let QUOTIENT denote the highest power of 2 that can be subtracted from the dividend.
if (ans == (1 << 31) && isPositive) return INT_MAX;
return isPositive ? ans : -ans; }
int main() { int dividend, divisor; printf("Enter the dividend and divisor: "); scanf("%d %d", ÷nd, &divisor); printf("The quotient is %d", divide(dividend, divisor)); return 0; }
// C++ program to divide two numbers using bit manipulation. #include <iostream> #include <climits>
using namespace std;
// Function to find the quotient. int divide(int dividend, int divisor) { // If the dividend and divisor are equal, the answer will always be 1. if (dividend == divisor) return 1;
// The answer is always positive if the dividend and divisor are of the same sign. bool isPositive = (dividend < 0 == divisor < 0);
// Taking positive values of the dividend and divisor. unsigned int absDividend = abs(dividend); unsigned int absDivisor = abs(divisor);
unsigned int ans = 0;
// While the dividend is greater than or equal to divisor. while (absDividend >= absDivisor) { int quotient = 0; while (absDividend > (absDivisor << (quotient + 1))) quotient++;
// This power of 2 that is found is added to the answer. ans += (1 << quotient);
// The dividend is reduced by the divisor multiplied by the power of 2 found absDividend -= (absDivisor << quotient); }
// In case the answer cannot be stored in the signed int. if (ans == (1 << 31) and isPositive) return INT_MAX;
// Returning the answer according to the sign. return isPositive ? ans : -ans; } int main() { int dividend, divisor;
// Taking user input. cout << "Enter the dividend and divisor: "; cin >> dividend >> divisor;
// Calling the function and printing the answer. cout << "The quotient is " << divide(dividend, divisor);
return 0; }
You can also try this code with Online C++ Compiler
if (ans == (1 << 31) && isPositive) return Integer.MAX_VALUE;
return isPositive ? ans : -ans; }
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("Enter the dividend and divisor: "); int dividend = scanner.nextInt(); int divisor = scanner.nextInt(); System.out.println("The quotient is " + divide(dividend, divisor)); } }
You can also try this code with Online Java Compiler
Why might dividing two integers lead to unexpected results in programming languages?
We can address the challenges of integer division, such as truncation of the fractional part and potential overflow or underflow issues, particularly in languages like C and Java.
How can I handle edge cases like division by zero or integer overflow when dividing integers in my code?
You can delve into best practices for handling division by zero, checking for overflow conditions, and using techniques like bit manipulation or binary search to handle large numbers more efficiently.
What are some alternative approaches to integer division beyond simple arithmetic operators?
We can explore alternative methods for dividing integers, such as using bit manipulation, binary search, or other mathematical techniques, and discuss their advantages and limitations in terms of performance and precision.
Conclusion
So, this blog discussed the problem of Divide Two Integers using 3 different approaches, discussing each approach's time and space complexity. To learn more, head over right now toCoding Ninjas Studio to practice problems on topics like Brute Force,Binary Search, and Bit Manipulation, and crack your interviews like a Ninja!
Practicing a bunch of questions is not enough in this competitive world. So go check out where you stand among your peers by taking our mock testsand see which areas need improvement.
In case of any comments or suggestions, feel free to post them in the comments section.