29. Divide Two Integers
Problem Description
This problem asks you to implement integer division between two numbers (dividend
and divisor
) without using the multiplication (*
), division (/
), or modulo (%
) operators.
The division should follow truncation rules toward zero, meaning:
- Positive results lose their decimal part (e.g.,
8.345
becomes8
) - Negative results also truncate toward zero (e.g.,
-2.7335
becomes-2
)
The function should return the quotient (the integer result of the division).
Key Constraints:
- The environment only supports 32-bit signed integers with range
[-2^31, 2^31 - 1]
- If the actual quotient exceeds
2^31 - 1
, return2^31 - 1
(overflow case) - If the actual quotient is less than
-2^31
, return-2^31
(underflow case)
Solution Strategy: The solution uses repeated subtraction with bit manipulation optimization. Since division is essentially counting how many times the divisor can be subtracted from the dividend, the naive approach would subtract the divisor one at a time. However, this is inefficient for large numbers.
The optimization uses bit shifting (doubling) to speed up the process:
- Convert both numbers to negative to avoid overflow issues (since
-2^31
cannot be represented as a positive 32-bit integer) - For each iteration, find the largest multiple of the divisor (using left shifts to double it) that can be subtracted from the current dividend
- Subtract this multiple and add the corresponding count to the answer
- Repeat until the remaining dividend is smaller than the divisor
- Apply the correct sign to the final result
The bit shifting approach reduces time complexity from O(dividend/divisor) to O(log(dividend/divisor)).
Intuition
Think about how we learned division in elementary school - it's essentially repeated subtraction. If we want to divide 20 by 3, we keep subtracting 3 from 20 until we can't subtract anymore: 20 - 3 - 3 - 3 - 3 - 3 - 3 = 2
. We subtracted 6 times, so 20 ÷ 3 = 6
.
The naive approach would be to implement this directly - keep subtracting the divisor from the dividend and count how many times we can do it. But imagine dividing 2^31 - 1
by 1
- we'd need to subtract over 2 billion times! This would definitely timeout.
The key insight is that we can subtract larger chunks at once. Instead of subtracting the divisor one at a time, what if we could subtract divisor * 2
, divisor * 4
, divisor * 8
, and so on? But wait - we can't use multiplication!
This is where bit shifting comes in. Left shifting a number by 1 position (x << 1
) doubles it without using multiplication. So we can create multiples of the divisor using shifts: divisor << 1
is 2 * divisor
, divisor << 2
is 4 * divisor
, etc.
The strategy becomes: find the largest multiple of the divisor (created by shifting) that still fits into the dividend, subtract it, and repeat. It's like taking the biggest possible bite each time instead of nibbling.
For example, dividing 20 by 3:
- Can we subtract
3 << 2 = 12
? Yes! Now we have20 - 12 = 8
, and we've effectively subtracted 4 times - Can we subtract
3 << 1 = 6
from 8? Yes! Now we have8 - 6 = 2
, adding 2 more to our count - Can we subtract 3 from 2? No, we're done. Total count:
4 + 2 = 6
One tricky detail: why convert everything to negative? In 32-bit signed integers, the range is [-2^31, 2^31 - 1]
. Notice that -2^31
has no positive counterpart - converting it to positive would overflow! By working with negatives throughout, we avoid this edge case since all positive numbers can be safely converted to negative.
Learn more about Math patterns.
Solution Approach
Let's walk through the implementation step by step:
1. Handle Special Cases:
if b == 1: return a if a == -(2**31) and b == -1: return 2**31 - 1
- If divisor is 1, the quotient is simply the dividend
- The overflow case:
-2^31 ÷ -1 = 2^31
, which exceeds our limit, so we return2^31 - 1
2. Determine the Sign:
sign = (a > 0 and b > 0) or (a < 0 and b < 0)
The result is positive if both numbers have the same sign, negative otherwise.
3. Convert to Negative Numbers:
a = -a if a > 0 else a b = -b if b > 0 else b
As discussed, we work with negatives to avoid overflow. Both a
(dividend) and b
(divisor) are converted to negative values.
4. Main Division Loop:
ans = 0 while a <= b: # Note: both are negative, so <= means |a| >= |b|
Continue as long as the absolute value of dividend is greater than or equal to the absolute value of divisor.
5. Find Largest Subtractable Multiple:
x = b cnt = 1 while x >= (-(2**30)) and a <= (x << 1): x <<= 1 cnt <<= 1
- Start with
x = b
(the divisor) andcnt = 1
(representing how many divisors this equals) - Double
x
using left shift (x << 1
) as long as:x >= -(2^30)
: Prevents overflow when doubling (since-(2^30) << 1 = -(2^31)
)a <= (x << 1)
: The doubled value still fits into the dividend
- Each time we double
x
, we also doublecnt
to track the multiple
6. Subtract and Accumulate:
a -= x ans += cnt
Subtract the largest multiple found from the dividend and add the corresponding count to our answer.
7. Apply Sign and Return:
return ans if sign else -ans
Apply the sign determined in step 2 to get the final result.
Example Walkthrough: 20 ÷ 3
- After conversion to negatives:
a = -20
,b = -3
- First iteration:
- Find largest multiple:
-3 → -6 → -12
(stop at -12 since -24 would exceed -20) - Subtract:
-20 - (-12) = -8
, addcnt = 4
to answer
- Find largest multiple:
- Second iteration:
- Find largest multiple:
-3 → -6
(stop at -6 since -12 would exceed -8) - Subtract:
-8 - (-6) = -2
, addcnt = 2
to answer
- Find largest multiple:
-2 > -3
, so loop ends- Result:
4 + 2 = 6
The time complexity is O(log n)
where n is the quotient, since we're essentially doing binary search on the quotient value through bit shifting.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through dividing 15 ÷ 4
using the bit-shifting solution approach:
Initial Setup:
- Dividend = 15, Divisor = 4
- Sign will be positive (both numbers are positive)
- Convert to negatives:
a = -15
,b = -4
- Initialize
ans = 0
Iteration 1:
- Start with
a = -15
, need to find largest multiple of-4
that fits - Build multiples by doubling:
x = -4
,cnt = 1
- Can we double? Check if
-15 <= (-4 << 1) = -8
? Yes! Sox = -8
,cnt = 2
- Can we double? Check if
-15 <= (-8 << 1) = -16
? No! Stop here
- Subtract the largest multiple:
a = -15 - (-8) = -7
- Add to answer:
ans = 0 + 2 = 2
Iteration 2:
- Start with
a = -7
, find largest multiple of-4
that fits - Build multiples:
x = -4
,cnt = 1
- Can we double? Check if
-7 <= (-4 << 1) = -8
? No! Stop here
- Subtract:
a = -7 - (-4) = -3
- Add to answer:
ans = 2 + 1 = 3
Check Loop Condition:
- Is
a = -3
still<= b = -4
? No! (Remember, both are negative) - Exit loop
Final Result:
- Apply sign (positive):
ans = 3
- Return
3
Verification: 15 ÷ 4 = 3
with remainder 3, which truncates to 3
✓
The key insight: instead of subtracting 4 three times (naive approach), we subtracted 8 once (which equals subtracting 4 twice) and then 4 once more - reducing our iterations from 3 to 2.
Solution Implementation
1class Solution:
2 def divide(self, dividend: int, divisor: int) -> int:
3 # Handle edge case: dividing by 1 returns the dividend itself
4 if divisor == 1:
5 return dividend
6
7 # Handle overflow case: INT_MIN / -1 would overflow, return INT_MAX
8 INT_MIN = -(2**31)
9 INT_MAX = 2**31 - 1
10 if dividend == INT_MIN and divisor == -1:
11 return INT_MAX
12
13 # Determine if result should be positive (same signs) or negative (different signs)
14 is_positive = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)
15
16 # Convert both numbers to negative to avoid overflow issues
17 # (negative range is larger than positive range in 32-bit integers)
18 dividend = -dividend if dividend > 0 else dividend
19 divisor = -divisor if divisor > 0 else divisor
20
21 # Perform division using bit manipulation and subtraction
22 quotient = 0
23 while dividend <= divisor: # Both are negative, so <= means abs(dividend) >= abs(divisor)
24 # Find the largest multiple of divisor that can be subtracted from dividend
25 current_divisor = divisor
26 current_quotient = 1
27
28 # Double the divisor using left shift until it exceeds dividend
29 # Check >= -(2^30) to prevent overflow when shifting
30 while current_divisor >= -(2**30) and dividend <= (current_divisor << 1):
31 current_divisor <<= 1 # Multiply by 2
32 current_quotient <<= 1 # Multiply by 2
33
34 # Subtract the largest found multiple from dividend
35 dividend -= current_divisor
36 quotient += current_quotient
37
38 # Apply the correct sign to the result
39 return quotient if is_positive else -quotient
40
1class Solution {
2 public int divide(int dividend, int divisor) {
3 // Fast path: dividing by 1 returns the dividend itself
4 if (divisor == 1) {
5 return dividend;
6 }
7
8 // Handle overflow case: MIN_VALUE / -1 would overflow to a value larger than MAX_VALUE
9 if (dividend == Integer.MIN_VALUE && divisor == -1) {
10 return Integer.MAX_VALUE;
11 }
12
13 // Determine if the result should be positive (same signs) or negative (different signs)
14 boolean isPositiveResult = (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0);
15
16 // Convert both numbers to negative to avoid overflow issues
17 // (negative range is larger than positive range in two's complement)
18 dividend = dividend > 0 ? -dividend : dividend;
19 divisor = divisor > 0 ? -divisor : divisor;
20
21 int quotient = 0;
22
23 // Perform division using bit manipulation and subtraction
24 while (dividend <= divisor) {
25 // Start with the divisor and count how many times we can double it
26 int currentDivisor = divisor;
27 int currentQuotient = 1;
28
29 // Double the divisor using left shift until it exceeds the dividend
30 // Check for overflow before shifting to prevent issues
31 while (currentDivisor >= (Integer.MIN_VALUE >> 1) && dividend <= (currentDivisor << 1)) {
32 currentDivisor <<= 1; // Double the divisor
33 currentQuotient <<= 1; // Double the quotient count
34 }
35
36 // Add the current quotient to the total
37 quotient += currentQuotient;
38
39 // Subtract the largest found multiple from the dividend
40 dividend -= currentDivisor;
41 }
42
43 // Apply the correct sign to the result
44 return isPositiveResult ? quotient : -quotient;
45 }
46}
47
1class Solution {
2public:
3 int divide(int dividend, int divisor) {
4 // Handle edge case: divisor is 1, return dividend as is
5 if (divisor == 1) {
6 return dividend;
7 }
8
9 // Handle overflow case: INT_MIN / -1 would overflow to INT_MAX + 1
10 if (dividend == INT_MIN && divisor == -1) {
11 return INT_MAX;
12 }
13
14 // Determine if result should be positive (both same sign)
15 bool isPositive = (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0);
16
17 // Convert both numbers to negative to avoid overflow issues
18 // (negative range is larger than positive range for int)
19 dividend = dividend > 0 ? -dividend : dividend;
20 divisor = divisor > 0 ? -divisor : divisor;
21
22 int quotient = 0;
23
24 // Perform division using bit manipulation and subtraction
25 while (dividend <= divisor) {
26 int currentDivisor = divisor;
27 int currentQuotient = 1;
28
29 // Double the divisor using left shift until it exceeds dividend
30 // Check for overflow before shifting
31 while (currentDivisor >= (INT_MIN >> 1) && dividend <= (currentDivisor << 1)) {
32 currentDivisor <<= 1; // Double the divisor
33 currentQuotient <<= 1; // Double the quotient count
34 }
35
36 // Add current quotient to result
37 quotient += currentQuotient;
38
39 // Subtract the largest found multiple from dividend
40 dividend -= currentDivisor;
41 }
42
43 // Apply the correct sign to the result
44 return isPositive ? quotient : -quotient;
45 }
46};
47
1/**
2 * Divides two integers without using multiplication, division, or mod operator
3 * @param dividend - The number to be divided
4 * @param divisor - The number to divide by
5 * @returns The quotient of dividend / divisor, truncated towards zero
6 */
7function divide(dividend: number, divisor: number): number {
8 // Handle edge case: divisor is 1
9 if (divisor === 1) {
10 return dividend;
11 }
12
13 // Handle edge case: overflow when dividing INT_MIN by -1
14 // Result would be 2^31 which exceeds INT_MAX (2^31 - 1)
15 if (dividend === -(2 ** 31) && divisor === -1) {
16 return 2 ** 31 - 1;
17 }
18
19 // Determine if result should be positive
20 // True if both numbers have the same sign
21 const isPositiveResult: boolean = (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0);
22
23 // Convert both numbers to negative to avoid overflow issues
24 // Negative range is larger than positive range in 32-bit integers
25 dividend = dividend > 0 ? -dividend : dividend;
26 divisor = divisor > 0 ? -divisor : divisor;
27
28 let quotient: number = 0;
29
30 // Repeatedly subtract divisor from dividend
31 while (dividend <= divisor) {
32 // Current subtractor and its corresponding quotient contribution
33 let currentDivisor: number = divisor;
34 let currentQuotient: number = 1;
35
36 // Double the divisor until it exceeds half of dividend
37 // Use bit shifting for efficient doubling
38 // Check >= -(2^30) to prevent overflow when shifting
39 while (currentDivisor >= -(2 ** 30) && dividend <= currentDivisor << 1) {
40 currentDivisor <<= 1; // Double the divisor
41 currentQuotient <<= 1; // Double the quotient contribution
42 }
43
44 // Add the current quotient contribution to total
45 quotient += currentQuotient;
46 // Subtract the current divisor from dividend
47 dividend -= currentDivisor;
48 }
49
50 // Apply the correct sign to the result
51 return isPositiveResult ? quotient : -quotient;
52}
53
Time and Space Complexity
The time complexity of this division algorithm is O(log a × log b)
, where a
is the dividend and b
is the divisor.
The algorithm works by repeatedly subtracting multiples of the divisor from the dividend. The outer while loop runs at most O(log a)
times because in each iteration, we subtract at least the divisor b
from a
, and in the worst case, we need a/b
iterations which is bounded by O(log a)
when we consider the doubling optimization.
The inner while loop performs bit shifting operations to find the largest multiple of b
(in the form of b × 2^k
) that can be subtracted from the current value of a
. This loop runs at most O(log b)
times in each iteration of the outer loop, as we double x
each time until it exceeds a
or reaches the boundary condition.
Since the inner loop runs O(log b)
times for each of the O(log a)
iterations of the outer loop, the total time complexity is O(log a × log b)
.
The space complexity is O(1)
as the algorithm only uses a constant amount of extra space for variables like sign
, ans
, x
, and cnt
, regardless of the input size.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Integer Overflow When Working with Positive Numbers
The Pitfall:
Many developers initially try to work with positive numbers by converting negative inputs to positive. This fails for the edge case where dividend = -2^31
because 2^31
cannot be represented in a 32-bit signed integer (maximum is 2^31 - 1
).
# WRONG approach - causes overflow
dividend = abs(dividend) # This fails when dividend = -2^31
divisor = abs(divisor)
The Solution:
Always convert to negative numbers instead, since the negative range [-2^31, -1]
is larger than the positive range [1, 2^31-1]
:
# CORRECT approach dividend = -dividend if dividend > 0 else dividend divisor = -divisor if divisor > 0 else divisor
2. Overflow During Bit Shifting
The Pitfall: When doubling the divisor using left shift, forgetting to check for potential overflow can cause incorrect results or runtime errors:
# WRONG - no overflow check while dividend <= (current_divisor << 1): current_divisor <<= 1 current_quotient <<= 1
The Solution:
Add a boundary check before shifting. Since we're working with negative numbers, check that the current value is >= -2^30
before doubling (because -2^30 << 1 = -2^31
, which is the limit):
# CORRECT - includes overflow prevention while current_divisor >= -(2**30) and dividend <= (current_divisor << 1): current_divisor <<= 1 current_quotient <<= 1
3. Incorrect Sign Determination Logic
The Pitfall: Using XOR or other complex logic for sign determination can be error-prone:
# Confusing and error-prone is_positive = (dividend < 0) ^ (divisor < 0) == 0
The Solution: Use clear, explicit logic that's easy to understand and verify:
# CORRECT and clear is_positive = (dividend > 0 and divisor > 0) or (dividend < 0 and divisor < 0)
4. Forgetting the Special Overflow Case
The Pitfall:
Not handling the specific case of -2^31 ÷ -1
, which mathematically equals 2^31
but exceeds the 32-bit signed integer range:
# WRONG - missing overflow handling
def divide(dividend, divisor):
# ... rest of the code without checking for INT_MIN / -1
The Solution: Always check for this case explicitly at the beginning:
# CORRECT if dividend == -(2**31) and divisor == -1: return 2**31 - 1
5. Incorrect Comparison Direction with Negative Numbers
The Pitfall: When working with negative numbers, the comparison operators can be counterintuitive:
# WRONG - using > instead of <= for negative numbers while dividend > divisor: # This is wrong when both are negative
The Solution: Remember that for negative numbers, a "smaller" value actually has a larger absolute value:
# CORRECT while dividend <= divisor: # -20 <= -3 means |20| >= |3|
What are the most two important steps in writing a depth first search function? (Select 2)
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!