Facebook Pixel

2303. Calculate Amount Paid in Taxes

EasyArraySimulation
Leetcode Link

Problem Description

You need to calculate the total tax amount based on a progressive tax bracket system.

You're given:

  • A 2D array brackets where each element brackets[i] = [upper_i, percent_i] represents:
    • upper_i: the upper bound of the i-th tax bracket (in dollars)
    • percent_i: the tax rate for that bracket (as a percentage)
  • The brackets are sorted in ascending order by their upper bounds
  • An integer income representing your total earnings

The tax calculation follows a progressive system:

  • The first upper_0 dollars of your income are taxed at percent_0%
  • The next chunk from upper_0 to upper_1 dollars is taxed at percent_1%
  • The next chunk from upper_1 to upper_2 dollars is taxed at percent_2%
  • This pattern continues for all brackets

For example, if brackets are [[10000, 10], [20000, 20]] and income is 15000:

  • First 10,000istaxedat1010,000 is taxed at 10% = 1,000
  • Next 5,000(from5,000 (from 10,000 to 15,000)istaxedat2015,000) is taxed at 20% = 1,000
  • Total tax = $2,000

The solution iterates through each bracket, calculating the taxable amount for that bracket as min(income, upper) - prev, where prev tracks the previous bracket's upper bound. This ensures we only tax the portion of income that falls within each bracket. The tax for each bracket is then accumulated and divided by 100 to convert from percentage to decimal.

Return the total tax amount as a floating-point number.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that we need to process the income in chunks, where each chunk corresponds to a tax bracket range. Since the brackets are already sorted by their upper bounds, we can process them sequentially.

Think of the income as being divided into layers, like a cake. Each layer gets taxed at a different rate. For each bracket, we need to figure out how much of our income falls within that bracket's range.

The challenge is determining how much income to tax at each bracket. For any bracket i, the taxable amount is the income that falls between the previous bracket's upper bound and the current bracket's upper bound. However, we need to be careful about two edge cases:

  1. If our income is less than the current bracket's upper bound, we should only tax up to our income amount, not the full bracket range
  2. If our income was already fully taxed in previous brackets, we shouldn't tax anything in the current bracket

This leads us to the formula: taxable_amount = max(0, min(income, upper) - prev)

  • min(income, upper) ensures we don't tax more than what we earned
  • Subtracting prev gives us only the portion that falls in the current bracket
  • max(0, ...) handles the case where our income was already fully covered by previous brackets

By maintaining a prev variable that tracks the upper bound of the last processed bracket, we can calculate the taxable amount for each bracket incrementally. We multiply this amount by the bracket's tax rate and accumulate the total tax.

The final division by 100 converts the percentage rates to decimal form for the final answer.

Solution Approach

The solution uses a simulation approach, processing each tax bracket sequentially to calculate the total tax.

Implementation Steps:

  1. Initialize Variables:

    • ans to accumulate the total tax amount (initially 0)
    • prev to track the upper bound of the previous bracket (initially 0)
  2. Iterate Through Brackets: For each bracket [upper, percent] in the brackets array:

    a. Calculate Taxable Amount for Current Bracket:

    • Use the formula: max(0, min(income, upper) - prev) * percent
    • min(income, upper) ensures we don't exceed the actual income
    • Subtracting prev gives us only the portion in this bracket
    • max(0, ...) handles cases where income is less than prev

    b. Accumulate Tax:

    • Add the calculated tax to ans

    c. Update Previous Upper Bound:

    • Set prev = upper for the next iteration
  3. Return Result:

    • Divide ans by 100 to convert from percentage to decimal format

Example Walkthrough:

Let's say brackets = [[10000, 10], [20000, 20], [30000, 30]] and income = 25000:

  • First bracket [10000, 10]:

    • Taxable: min(25000, 10000) - 0 = 10000
    • Tax: 10000 * 10 = 100000
    • Update: prev = 10000
  • Second bracket [20000, 20]:

    • Taxable: min(25000, 20000) - 10000 = 10000
    • Tax: 10000 * 20 = 200000
    • Update: prev = 20000
  • Third bracket [30000, 30]:

    • Taxable: min(25000, 30000) - 20000 = 5000
    • Tax: 5000 * 30 = 150000
    • Update: prev = 30000
  • Total: (100000 + 200000 + 150000) / 100 = 4500.0

The algorithm runs in O(n) time where n is the number of brackets, with O(1) space complexity.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a simple example with brackets = [[3, 50], [7, 10], [12, 25]] and income = 10.

Initial Setup:

  • ans = 0 (total tax accumulator)
  • prev = 0 (tracks previous bracket upper bound)

Processing Each Bracket:

Bracket 1: [3, 50]

  • Income range for this bracket: 0to0 to 3
  • Taxable amount: min(10, 3) - 0 = 3 - 0 = 3
  • Tax calculation: 3 * 50 = 150
  • Running total: ans = 0 + 150 = 150
  • Update: prev = 3

Bracket 2: [7, 10]

  • Income range for this bracket: 3to3 to 7
  • Taxable amount: min(10, 7) - 3 = 7 - 3 = 4
  • Tax calculation: 4 * 10 = 40
  • Running total: ans = 150 + 40 = 190
  • Update: prev = 7

Bracket 3: [12, 25]

  • Income range for this bracket: 7to7 to 12
  • Taxable amount: min(10, 12) - 7 = 10 - 7 = 3
  • Tax calculation: 3 * 25 = 75
  • Running total: ans = 190 + 75 = 265
  • Update: prev = 12

Final Result:

  • Total tax: 265 / 100 = 2.65

The key insight is that for each bracket, we calculate how much of our income falls within that bracket's range by taking the minimum of our income and the bracket's upper bound, then subtracting what was already taxed in previous brackets. This ensures each dollar is taxed exactly once at the appropriate rate.

Solution Implementation

1from typing import List
2
3class Solution:
4    def calculateTax(self, brackets: List[List[int]], income: int) -> float:
5        """
6        Calculate the tax amount based on progressive tax brackets.
7      
8        Args:
9            brackets: List of [upper_bound, tax_percentage] pairs representing tax brackets
10            income: The total income to calculate tax for
11          
12        Returns:
13            The total tax amount as a float
14        """
15        total_tax = 0
16        previous_upper_bound = 0
17      
18        # Process each tax bracket
19        for upper_bound, tax_percentage in brackets:
20            # Calculate taxable income for this bracket
21            # It's the minimum of remaining income and bracket range
22            taxable_in_bracket = max(0, min(income, upper_bound) - previous_upper_bound)
23          
24            # Add tax for this bracket to total
25            total_tax += taxable_in_bracket * tax_percentage
26          
27            # Update the previous upper bound for next iteration
28            previous_upper_bound = upper_bound
29      
30        # Convert from percentage to decimal (divide by 100)
31        return total_tax / 100
32
1class Solution {
2    /**
3     * Calculates the total tax amount based on progressive tax brackets.
4     * 
5     * @param brackets A 2D array where each element contains [upperBound, taxRate]
6     *                 representing the upper limit of income for that bracket and its tax percentage
7     * @param income   The total income to calculate tax for
8     * @return         The total tax amount as a double value
9     */
10    public double calculateTax(int[][] brackets, int income) {
11        // Total tax accumulated across all brackets
12        int totalTax = 0;
13      
14        // Previous bracket's upper bound (starts at 0 for the first bracket)
15        int previousUpperBound = 0;
16      
17        // Iterate through each tax bracket
18        for (int[] bracket : brackets) {
19            // Extract the upper bound and tax rate for current bracket
20            int currentUpperBound = bracket[0];
21            int taxRate = bracket[1];
22          
23            // Calculate taxable income for this bracket:
24            // - Take the minimum of remaining income and current upper bound
25            // - Subtract the previous upper bound to get income in this bracket only
26            // - Ensure non-negative value with Math.max
27            int taxableIncomeInBracket = Math.max(0, Math.min(income, currentUpperBound) - previousUpperBound);
28          
29            // Add tax for this bracket (taxable income * tax rate)
30            totalTax += taxableIncomeInBracket * taxRate;
31          
32            // Update previous upper bound for next iteration
33            previousUpperBound = currentUpperBound;
34        }
35      
36        // Convert from percentage to decimal (divide by 100)
37        return totalTax / 100.0;
38    }
39}
40
1class Solution {
2public:
3    double calculateTax(vector<vector<int>>& brackets, int income) {
4        // Initialize total tax amount and previous bracket upper limit
5        int totalTax = 0;
6        int previousUpperLimit = 0;
7      
8        // Iterate through each tax bracket
9        for (auto& bracket : brackets) {
10            // Extract current bracket's upper limit and tax percentage
11            int currentUpperLimit = bracket[0];
12            int taxPercentage = bracket[1];
13          
14            // Calculate taxable income for this bracket
15            // It's the minimum of (remaining income, bracket range) but at least 0
16            int taxableIncome = max(0, min(income, currentUpperLimit) - previousUpperLimit);
17          
18            // Add tax for this bracket (taxable income * percentage)
19            totalTax += taxableIncome * taxPercentage;
20          
21            // Update previous upper limit for next iteration
22            previousUpperLimit = currentUpperLimit;
23        }
24      
25        // Convert from percentage to decimal (divide by 100)
26        return totalTax / 100.0;
27    }
28};
29
1/**
2 * Calculates the total tax based on progressive tax brackets
3 * @param brackets - Array of tax brackets, each containing [upperBound, taxPercentage]
4 * @param income - The total income to calculate tax for
5 * @returns The total tax amount
6 */
7function calculateTax(brackets: number[][], income: number): number {
8    // Initialize total tax amount
9    let totalTax: number = 0;
10  
11    // Track the previous bracket's upper bound (starts at 0)
12    let previousUpperBound: number = 0;
13  
14    // Process each tax bracket
15    for (const [upperBound, taxPercentage] of brackets) {
16        // Calculate taxable income for current bracket:
17        // - Take the minimum of income and current upper bound
18        // - Subtract the previous upper bound to get income in this bracket
19        // - Ensure it's not negative with Math.max(0, ...)
20        const taxableIncomeInBracket: number = Math.max(0, Math.min(income, upperBound) - previousUpperBound);
21      
22        // Add tax for this bracket (multiply by percentage)
23        totalTax += taxableIncomeInBracket * taxPercentage;
24      
25        // Update previous upper bound for next iteration
26        previousUpperBound = upperBound;
27    }
28  
29    // Convert from percentage to decimal (divide by 100)
30    return totalTax / 100;
31}
32

Time and Space Complexity

The time complexity is O(n), where n is the length of the brackets list. This is because the algorithm iterates through each bracket exactly once in a single loop, performing constant-time operations (comparisons, arithmetic operations, and assignments) for each bracket.

The space complexity is O(1). The algorithm only uses a fixed amount of extra space for variables ans and prev, regardless of the input size. No additional data structures that scale with the input are created.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Forgetting to Convert Percentage to Decimal

One of the most common mistakes is forgetting to divide the final result by 100. Since the tax rates are given as percentages (e.g., 20 means 20%), the accumulated tax needs to be converted to the actual dollar amount.

Incorrect:

def calculateTax(self, brackets: List[List[int]], income: int) -> float:
    total_tax = 0
    previous_upper_bound = 0
  
    for upper_bound, tax_percentage in brackets:
        taxable_in_bracket = max(0, min(income, upper_bound) - previous_upper_bound)
        total_tax += taxable_in_bracket * tax_percentage
        previous_upper_bound = upper_bound
  
    return total_tax  # Missing division by 100!

Solution: Always remember to divide by 100 at the end, or alternatively, convert percentages to decimals at the beginning.

2. Not Handling Early Termination

When income is less than the upper bound of a bracket, continuing to process remaining brackets wastes computation time. While the current solution handles this correctly with min(income, upper_bound), an optimization would be to break early.

Optimized Solution:

def calculateTax(self, brackets: List[List[int]], income: int) -> float:
    total_tax = 0
    previous_upper_bound = 0
  
    for upper_bound, tax_percentage in brackets:
        if income <= previous_upper_bound:
            break  # No more income to tax
          
        taxable_in_bracket = min(income, upper_bound) - previous_upper_bound
        total_tax += taxable_in_bracket * tax_percentage
        previous_upper_bound = upper_bound
      
        if income <= upper_bound:
            break  # All income has been taxed
  
    return total_tax / 100

3. Integer Division Issues in Other Languages

If implementing in languages like C++ or Java, using integer division could lead to precision loss. Always ensure floating-point arithmetic when dealing with the final result.

Example in Java (incorrect):

return totalTax / 100;  // Integer division if totalTax is int

Correct approach:

return totalTax / 100.0;  // Forces floating-point division

4. Not Initializing Previous Upper Bound to Zero

Forgetting to initialize previous_upper_bound to 0 or starting it with the wrong value will cause incorrect calculations for the first bracket.

Incorrect:

def calculateTax(self, brackets: List[List[int]], income: int) -> float:
    total_tax = 0
    # Missing initialization of previous_upper_bound!
  
    for i, (upper_bound, tax_percentage) in enumerate(brackets):
        if i == 0:
            taxable_in_bracket = min(income, upper_bound)
        else:
            # previous_upper_bound is undefined here!
            taxable_in_bracket = min(income, upper_bound) - previous_upper_bound
        # ...

5. Misunderstanding the Bracket System

A conceptual pitfall is thinking that if your income falls in a certain bracket, ALL of it gets taxed at that rate. This is incorrect - only the portion within each bracket gets taxed at that bracket's rate.

Wrong Mental Model: "If I earn 25,000andfallinthe3025,000 and fall in the 30% bracket, I pay 30% on all 25,000"

Correct Understanding: "Each portion of my income gets taxed at its corresponding bracket rate"

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

Which type of traversal does breadth first search do?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More