diff --git a/DIRECTORY.md b/DIRECTORY.md index 6eb9887f..84bba95c 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -704,6 +704,8 @@ * [Test Pascals Triangle](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/pascals_triangle/test_pascals_triangle.py) * Perfect Square * [Test Perfect Squares](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/perfect_square/test_perfect_squares.py) + * Rectangle Area + * [Test Compute Area](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/rectangle_area/test_compute_area.py) * Super Size * [Test Super Size](https://github.com/BrianLusina/PythonSnips/blob/master/pymath/super_size/test_super_size.py) * Triangles diff --git a/puzzles/arrays/max_consecutive_ones/README.md b/puzzles/arrays/max_consecutive_ones/README.md index 1c30035d..26f1d1ef 100644 --- a/puzzles/arrays/max_consecutive_ones/README.md +++ b/puzzles/arrays/max_consecutive_ones/README.md @@ -19,6 +19,16 @@ Explanation: [0,0,1,1,*1*,*1*,1,1,1,*1*,1,1,0,0,0,1,1,1,1] starred numbers were flipped from 0 to 1. The longest subarray is [1,1,1,1,1,1,1,1,1,1]. ``` +## Max consecutive ones two + +You are given a binary array nums (an array that contains only 0s and 1s). Your task is to find the maximum number of +consecutive 1s in the array and return it. + +### Constraints + +- 1 ≤ `nums.length` ≤ 10^3 +- `nums[i` is either 0 or 1 + ## Related Topics - Array diff --git a/puzzles/arrays/max_consecutive_ones/__init__.py b/puzzles/arrays/max_consecutive_ones/__init__.py index a1b8d3ba..4c08328f 100644 --- a/puzzles/arrays/max_consecutive_ones/__init__.py +++ b/puzzles/arrays/max_consecutive_ones/__init__.py @@ -20,3 +20,36 @@ def longest_ones(nums: List[int], k: int) -> int: left += 1 return right - left + 1 + +def find_max_consecutive_ones(nums: List[int]) -> int: + """ + Finds the maximum consecutive ones in a binary array and returns it. + + The most straightforward way to solve this is to use a single pass through the array, keeping track of two values + as we go. First, we need a counter for the current streak of consecutive 1s we're seeing. Second, we need to + remember the maximum streak we've encountered so far. + + As we examine each element, if we see a 1, we increment our current streak counter. If we see a 0, that breaks our + streak, so we reset the counter to 0. Importantly, every time we update our current streak, we check whether it's + larger than our maximum and update the maximum if needed. + + Time complexity is O(n) where n is the length of the input array + Space complexity is O(1) as no extra space is required + + Args: + nums(list): a list of 1s and 0s. + Returns: + int: maximum number of consecutive 1s in the nums binary array + """ + if len(nums) == 0: + return 0 + max_ones = 0 + current_consecutive = 0 + + for num in nums: + if num == 1: + current_consecutive += 1 + max_ones = max(max_ones, current_consecutive) + else: + current_consecutive = 0 + return max_ones diff --git a/puzzles/arrays/max_consecutive_ones/test_max_consecutive_ones.py b/puzzles/arrays/max_consecutive_ones/test_max_consecutive_ones.py index 84223de8..2c235be1 100644 --- a/puzzles/arrays/max_consecutive_ones/test_max_consecutive_ones.py +++ b/puzzles/arrays/max_consecutive_ones/test_max_consecutive_ones.py @@ -1,23 +1,29 @@ import unittest - -from . import longest_ones +from typing import List +from parameterized import parameterized +from puzzles.arrays.max_consecutive_ones import longest_ones, find_max_consecutive_ones class MaxConsecutiveOnesTestCase(unittest.TestCase): - def test_one(self): - """should return 6 from nums = [1,1,1,0,0,0,1,1,1,1,0], k = 2""" - nums = [1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0] - k = 2 - expected = 6 + + @parameterized.expand([ + ([1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0], 2, 6), + ([0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1], 3, 10), + ]) + def test_longest_ones(self, nums: List[int], k: int, expected: int): actual = longest_ones(nums, k) self.assertEqual(expected, actual) - def test_two(self): - """should return 10 from nums = [0,0,1,1,0,0,1,1,1,0,1,1,0,0,0,1,1,1,1], k = 3""" - nums = [0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1] - k = 3 - expected = 10 - actual = longest_ones(nums, k) + @parameterized.expand([ + ([1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0], 4), + ([0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1], 4), + ([1,1,0,0,1,1,1,0,0,1,0], 3), + ([1,1,0,0,1,1], 2), + ([1,1,1,0,1,1,1,1], 4), + ([0,0,0,0], 0), + ]) + def test_find_max_consecutive_ones(self, nums: List[int], expected: int): + actual = find_max_consecutive_ones(nums) self.assertEqual(expected, actual) diff --git a/pymath/rectangle_area/README.md b/pymath/rectangle_area/README.md new file mode 100644 index 00000000..bff60757 --- /dev/null +++ b/pymath/rectangle_area/README.md @@ -0,0 +1,24 @@ +# Rectangle Area + +You are given the coordinates of two axis-aligned rectangles in a 2D plane. Your task is to calculate the total area +covered by both rectangles. + +The first rectangle is specified by the coordinates of its bottom-left corner (ax1, ay1) and top-right corner (ay1, ay2). + +Similarly, the second rectangle is defined by its bottom-left corner (bx1, by1) and top-right corner (bx2, by2). + +> Note: The rectangles may overlap. + +## Constraints + +1. -10^4 ≤ ax1 ≤ ax2 ≤ 10^4 +2. −10^4 ≤ ay1 ≤ ay2 ≤ 10^4 +3. −10^4 ≤ bx1 ≤ bx2 ≤10^4 +4. −10^4 ≤ by1 ≤ by2 ≤ 10^4 + +## Examples + +![Example 1](./images/examples/rectangle_area_example_1.png) +![Example 2](./images/examples/rectangle_area_example_2.png) +![Example 3](./images/examples/rectangle_area_example_3.png) +![Example 4](./images/examples/rectangle_area_example_4.png) diff --git a/pymath/rectangle_area/__init__.py b/pymath/rectangle_area/__init__.py new file mode 100644 index 00000000..6f3de46e --- /dev/null +++ b/pymath/rectangle_area/__init__.py @@ -0,0 +1,33 @@ +def compute_area( + ax1: int, ay1: int, ax2: int, ay2: int, bx1: int, by1: int, bx2: int, by2: int +): + # 1. Calculate the area of each individual rectangle + area_a = (ax2 - ax1) * (ay2 - ay1) + area_b = (bx2 - bx1) * (by2 - by1) + + # 2. Calculate the area of the overlap (A intersect B) + + # Determine the coordinates of the overlap rectangle: (ix1, iy1) to (ix2, iy2) + + # The left edge of the overlap is the max of the two left edges + ix1 = max(ax1, bx1) + # The right edge of the overlap is the min of the two right edges + ix2 = min(ax2, bx2) + + # The bottom edge of the overlap is the max of the two bottom edges + iy1 = max(ay1, by1) + # The top edge of the overlap is the min of the two top edges + iy2 = min(ay2, by2) + + # Calculate the width and height of the overlap + overlap_width = max(0, ix2 - ix1) + overlap_height = max(0, iy2 - iy1) + + # The max(0, ...) ensures that if the rectangles do not overlap + # (e.g., ix2 < ix1), the width/height is 0, and the overlap_area is 0. + overlap_area = overlap_width * overlap_height + + # 3. Apply the Inclusion-Exclusion Principle + total_area = area_a + area_b - overlap_area + + return total_area diff --git a/pymath/rectangle_area/test_compute_area.py b/pymath/rectangle_area/test_compute_area.py new file mode 100644 index 00000000..4836300d --- /dev/null +++ b/pymath/rectangle_area/test_compute_area.py @@ -0,0 +1,33 @@ +import unittest +from parameterized import parameterized +from pymath.rectangle_area import compute_area + + +class RectangleAreaTestCase(unittest.TestCase): + @parameterized.expand( + [ + (0, 0, 1, 1, 2, 2, 3, 3, 2), + (0, 0, 2, 2, 1, 1, 3, 3, 7), + (-1, -1, 2, 2, 0, 0, 1, 1, 9), + (0, 0, 0, 0, 1, 1, 2, 2, 1), + (-8918, -419, -7715, 577, -8918, -419, -7715, 577, 1198188), + ] + ) + def test_compute_area( + self, + ax1: int, + ay1: int, + ax2: int, + ay2: int, + bx1: int, + by1: int, + bx2: int, + by2: int, + expected, + ): + actual = compute_area(ax1, ay1, ax2, ay2, bx1, by1, bx2, by2) + self.assertEqual(expected, actual) + + +if __name__ == "__main__": + unittest.main()