diff --git a/.github/workflows/linter-python.yml b/.github/workflows/linter-python.yml index 528f4e5..fa086d8 100644 --- a/.github/workflows/linter-python.yml +++ b/.github/workflows/linter-python.yml @@ -28,14 +28,14 @@ jobs: - name: Lint Python code using Makefile run: | - make lint-python + make lint-py - name: Format check Python code using Makefile run: | - make format-python + make format-py # Check if any files were modified by formatting if ! git diff --exit-code; then echo "Code formatting issues found. Please run 'make \ - format-python' locally." + format-py' locally." exit 1 fi diff --git a/.github/workflows/presubmit-python.yml b/.github/workflows/presubmit-python.yml index 59b8af6..40aa651 100644 --- a/.github/workflows/presubmit-python.yml +++ b/.github/workflows/presubmit-python.yml @@ -92,7 +92,7 @@ jobs: - name: Lint Python code if: steps.detect-changes.outputs.has_python_changes == 'true' - run: make lint-python + run: make lint-py - name: Run Python tests for changed problems if: > diff --git a/.gitignore b/.gitignore index def7ca7..fea407f 100644 --- a/.gitignore +++ b/.gitignore @@ -171,3 +171,6 @@ build/ # Test Runner test_runner test_runner.dSYM/ + +# Problem generation script (not tracked) +generate_problem.py diff --git a/Makefile b/Makefile index 093a238..7420474 100644 --- a/Makefile +++ b/Makefile @@ -173,7 +173,7 @@ test-py\:%: format: @make format-cpp @echo "" - @make format-python + @make format-py .PHONY: format-cpp format-cpp: @@ -185,8 +185,8 @@ format-cpp: echo "$(call color_red,clang-format not found. Please install it to format C++ files.)"; \ fi -.PHONY: format-python -format-python: +.PHONY: format-py +format-py: @echo "Formatting Python files..." @if command -v ruff >/dev/null; then \ ruff format $(PROBLEMS_DIR); \ @@ -202,7 +202,7 @@ format-python: lint: @make lint-cpp @echo "" - @make lint-python + @make lint-py .PHONY: lint-cpp lint-cpp: @@ -216,8 +216,8 @@ lint-cpp: echo "$(call color_red,clang-tidy not found. Please install it to lint C++ files.)"; \ fi -.PHONY: lint-python -lint-python: +.PHONY: lint-py +lint-py: @echo "Linting Python files..." @if command -v ruff >/dev/null; then \ ruff check $(PROBLEMS_DIR); \ @@ -365,10 +365,10 @@ help: @echo "$(call color_yellow,Code Quality Targets:)" @echo " format - Format all code (C++ and Python)" @echo " format-cpp - Format C++ code only" - @echo " format-python - Format Python code only" + @echo " format-py - Format Python code only" @echo " lint - Lint all code (C++ and Python)" @echo " lint-cpp - Lint C++ code only" - @echo " lint-python - Lint Python code only" + @echo " lint-py - Lint Python code only" @echo "" @echo "$(call color_yellow,Utility Targets:)" @echo " clean - Clean build artifacts" diff --git a/README.md b/README.md index f83c998..8cc9aa4 100644 --- a/README.md +++ b/README.md @@ -15,8 +15,8 @@ ### 📊 Repository Stats [![Last Commit](https://img.shields.io/github/last-commit/mathusanm6/LeetCode?style=for-the-badge&logo=git&logoColor=white&color=blue)](https://github.com/mathusanm6/LeetCode/commits/main) -[![C++ Solutions](https://img.shields.io/badge/C%2B%2B%20Solutions-5-blue?style=for-the-badge&logo=cplusplus&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems) -[![Python Solutions](https://img.shields.io/badge/Python%20Solutions-5-blue?style=for-the-badge&logo=python&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems) +[![C++ Solutions](https://img.shields.io/badge/C%2B%2B%20Solutions-6-blue?style=for-the-badge&logo=cplusplus&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems) +[![Python Solutions](https://img.shields.io/badge/Python%20Solutions-6-blue?style=for-the-badge&logo=python&logoColor=white)](https://github.com/mathusanm6/LeetCode/tree/main/problems) @@ -130,9 +130,9 @@ make lint # Language-specific operations make format-cpp # Format C++ files with clang-format -make format-python # Format Python files with ruff +make format-py # Format Python files with ruff make lint-cpp # Lint C++ files with clang-tidy -make lint-python # Lint Python files with ruff +make lint-py # Lint Python files with ruff ``` ### 🔄 Continuous Integration @@ -186,6 +186,7 @@ This repository covers a comprehensive range of algorithmic patterns and data st | 1 | [Two Sum](https://leetcode.com/problems/two-sum/) | [Python](./problems/two_sum/two_sum.py), [C++](./problems/two_sum/two_sum.cc) | _O(n)_ | _O(n)_ | Easy | | | | 49 | [Group Anagrams](https://leetcode.com/problems/group-anagrams/) | [Python](./problems/group_anagrams/group_anagrams.py), [C++](./problems/group_anagrams/group_anagrams.cc) | _O(n * k log k)_ | _O(n)_ | Medium | | For C++, the complexity is _O(n * k log k)_, where n is the number of strings and k is the maximum length of a string. But for Python, the complexity is _O(n * k)_ as there is no sorting involved. | | 217 | [Contains Duplicate](https://leetcode.com/problems/contains-duplicate/) | [Python](./problems/contains_duplicate/contains_duplicate.py), [C++](./problems/contains_duplicate/contains_duplicate.cc) | _O(n)_ | _O(n)_ | Easy | | | +| 2303 | [Calculate Amount Paid In Taxes](https://leetcode.com/problems/calculate-amount-paid-in-taxes/) | [Python](./problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.py), [C++](./problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.cc) | _O(n)_ | _O(1)_ | Easy | | | ## Two Pointers diff --git a/hooks/pre-commit b/hooks/pre-commit index 7dfe709..3b61501 100755 --- a/hooks/pre-commit +++ b/hooks/pre-commit @@ -179,7 +179,7 @@ if [ "$HAS_PYTHON_FILES" = true ] || [ "$HAS_CPP_FILES" = true ]; then LINT_SUCCESS=true if [ "$HAS_PYTHON_FILES" = true ]; then print_status "Linting Python files..." - if ! make lint-python; then + if ! make lint-py; then LINT_SUCCESS=false fi fi diff --git a/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.cc b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.cc new file mode 100644 index 0000000..93d624e --- /dev/null +++ b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.cc @@ -0,0 +1,37 @@ +#include "calculate_amount_paid_in_taxes.h" + +#include +#include + +using std::min; +using std::vector; + +double calculateAmountPaidInTaxes(const vector>& brackets, const int income) { + double totalTax = 0.0; + + int incomeRemaining = income; + int previousUpperLimit = 0; + + for (const auto& bracket : brackets) { + const int upperLimit = bracket[0]; + const int ratePercent = bracket[1]; + + // If no income remains, break early. + if (incomeRemaining <= 0) { + return totalTax; + } + + // Calculate the taxable amount in the current bracket. + const int bracketSize = upperLimit - previousUpperLimit; + const int taxableAmount = min(incomeRemaining, bracketSize); + + // Add the tax for this bracket. + totalTax += taxableAmount * (ratePercent / 100.0); + + // Update remaining income and previous upper limit. + incomeRemaining -= taxableAmount; + previousUpperLimit = upperLimit; + } + + return totalTax; +} \ No newline at end of file diff --git a/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.h b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.h new file mode 100644 index 0000000..281c242 --- /dev/null +++ b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.h @@ -0,0 +1,3 @@ +#include + +double calculateAmountPaidInTaxes(const std::vector>& brackets, const int income); \ No newline at end of file diff --git a/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.py b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.py new file mode 100644 index 0000000..bc57b3f --- /dev/null +++ b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.py @@ -0,0 +1,26 @@ +from typing import List + + +def calculateAmountPaidInTaxes(brackets: List[List[int]], income: int) -> float: + total_tax = 0.0 + + income_remaining = income + previous_upper_limit = 0 + + for upper_limit, rate_percent in brackets: + # If no income remains, break early. + if income_remaining <= 0: + return total_tax + + # Calculate the taxable amount in the current bracket. + bracket_size = upper_limit - previous_upper_limit + taxable_amount = min(income_remaining, bracket_size) + + # Add the tax for this bracket. + total_tax += taxable_amount * (rate_percent / 100.0) + + # Update remaining income and previous upper limit. + income_remaining -= taxable_amount + previous_upper_limit = upper_limit + + return total_tax diff --git a/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes_test.cc b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes_test.cc new file mode 100644 index 0000000..cda7227 --- /dev/null +++ b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes_test.cc @@ -0,0 +1,38 @@ +#include "calculate_amount_paid_in_taxes.h" + +#include +#include +#include + +struct CalculateAmountPaidInTaxesCase { + std::string test_name; + const std::vector> brackets; + const int income; + const double expected; +}; + +using CalculateAmountPaidInTaxesTest = ::testing::TestWithParam; + +TEST_P(CalculateAmountPaidInTaxesTest, TestCases) { + CalculateAmountPaidInTaxesCase testCase = GetParam(); + const auto result = calculateAmountPaidInTaxes(testCase.brackets, testCase.income); + EXPECT_EQ(result, testCase.expected); +} + +INSTANTIATE_TEST_SUITE_P( + CalculateAmountPaidInTaxesTestCases, CalculateAmountPaidInTaxesTest, + ::testing::Values(CalculateAmountPaidInTaxesCase{.test_name = "Example1", + .brackets = {{3, 50}, {7, 10}, {12, 25}}, + .income = 10, + .expected = 2.65000}, + CalculateAmountPaidInTaxesCase{.test_name = "Example2", + .brackets = {{1, 0}, {4, 25}, {5, 50}}, + .income = 2, + .expected = 0.25000}, + CalculateAmountPaidInTaxesCase{.test_name = "Example3", + .brackets = {{2, 50}}, + .income = 0, + .expected = 0.00000}), + [](const testing::TestParamInfo &info) { + return info.param.test_name; + }); diff --git a/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes_test.py b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes_test.py new file mode 100644 index 0000000..03699e9 --- /dev/null +++ b/problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes_test.py @@ -0,0 +1,22 @@ +"""Test cases for the calculate_amount_paid_in_taxes function.""" + +import pytest + +from calculate_amount_paid_in_taxes import calculateAmountPaidInTaxes + + +@pytest.mark.parametrize( + "brackets, income, expected", + [ + ([[3, 50], [7, 10], [12, 25]], 10, 2.65000), + ([[1, 0], [4, 25], [5, 50]], 2, 0.25000), + ([[2, 50]], 0, 0.00000), + ], + ids=[ + "example1", + "example2", + "example3", + ], +) +def test_calculate_amount_paid_in_taxes(brackets, income, expected): + assert calculateAmountPaidInTaxes(brackets, income) == expected diff --git a/problems/calculate_amount_paid_in_taxes/config.yml b/problems/calculate_amount_paid_in_taxes/config.yml new file mode 100644 index 0000000..6bd64a6 --- /dev/null +++ b/problems/calculate_amount_paid_in_taxes/config.yml @@ -0,0 +1,17 @@ +problem: + number: 2303 + title: "Calculate Amount Paid In Taxes" + leetcode_url: "https://leetcode.com/problems/calculate-amount-paid-in-taxes/" + difficulty: "easy" + tags: [Arrays & Hashing] + +solutions: + python: "problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.py" + cpp: "problems/calculate_amount_paid_in_taxes/calculate_amount_paid_in_taxes.cc" + +complexity: + time: "O(n)" + space: "O(1)" + +notes: "" +readme_link: ""