diff --git a/other/pascal_triangle.py b/other/pascal_triangle.py index 5cc3cee8a..7f6555f9c 100644 --- a/other/pascal_triangle.py +++ b/other/pascal_triangle.py @@ -1,13 +1,10 @@ """ -This implementation demonstrates how to generate the -elements of a Pascal's triangle. The element having -a row index of r and column index of c can be derived -as follows: +This implementation demonstrates how to generate the elements of a Pascal's triangle. +The element havingva row index of r and column index of c can be derivedvas follows: triangle[r][c] = triangle[r-1][c-1]+triangle[r-1][c] -What is Pascal's triangle? -- It is a triangular array containing binomial coefficients. -Refer to (https://en.wikipedia.org/wiki/Pascal%27s_triangle) -for more info about this triangle. + +A Pascal's triangle is a triangular array containing binomial coefficients. +https://en.wikipedia.org/wiki/Pascal%27s_triangle """ @@ -38,6 +35,8 @@ def print_pascal_triangle(num_rows: int) -> None: def generate_pascal_triangle(num_rows: int) -> list[list[int]]: """ Create Pascal's triangle for different number of rows + >>> generate_pascal_triangle(0) + [] >>> generate_pascal_triangle(1) [[1]] >>> generate_pascal_triangle(2) @@ -48,7 +47,26 @@ def generate_pascal_triangle(num_rows: int) -> list[list[int]]: [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1]] >>> generate_pascal_triangle(5) [[1], [1, 1], [1, 2, 1], [1, 3, 3, 1], [1, 4, 6, 4, 1]] + >>> generate_pascal_triangle(-5) + Traceback (most recent call last): + ... + ValueError: The input value of 'num_rows' should be greater than or equal to 0 + >>> generate_pascal_triangle(7.89) + Traceback (most recent call last): + ... + TypeError: The input value of 'num_rows' should be 'int' """ + + if not isinstance(num_rows, int): + raise TypeError("The input value of 'num_rows' should be 'int'") + + if num_rows == 0: + return [] + elif num_rows < 0: + raise ValueError( + "The input value of 'num_rows' should be greater than or equal to 0" + ) + triangle: list[list[int]] = [] for current_row_idx in range(num_rows): current_row = populate_current_row(triangle, current_row_idx) @@ -90,7 +108,82 @@ def calculate_current_element( current_row[current_col_idx] = above_to_left_elt + above_to_right_elt +def generate_pascal_triangle_optimized(num_rows: int) -> list[list[int]]: + """ + This function returns a matrix representing the corresponding pascal's triangle + according to the given input of number of rows of Pascal's triangle to be generated. + It reduces the operations done to generate a row by half + by eliminating redundant calculations. + + :param num_rows: Integer specifying the number of rows in the Pascal's triangle + :return: 2-D List (matrix) representing the Pascal's triangle + + Return the Pascal's triangle of given rows + >>> generate_pascal_triangle_optimized(3) + [[1], [1, 1], [1, 2, 1]] + >>> generate_pascal_triangle_optimized(1) + [[1]] + >>> generate_pascal_triangle_optimized(0) + [] + >>> generate_pascal_triangle_optimized(-5) + Traceback (most recent call last): + ... + ValueError: The input value of 'num_rows' should be greater than or equal to 0 + >>> generate_pascal_triangle_optimized(7.89) + Traceback (most recent call last): + ... + TypeError: The input value of 'num_rows' should be 'int' + """ + + if not isinstance(num_rows, int): + raise TypeError("The input value of 'num_rows' should be 'int'") + + if num_rows == 0: + return [] + elif num_rows < 0: + raise ValueError( + "The input value of 'num_rows' should be greater than or equal to 0" + ) + + result: list[list[int]] = [[1]] + + for row_index in range(1, num_rows): + temp_row = [0] + result[-1] + [0] + row_length = row_index + 1 + # Calculate the number of distinct elements in a row + distinct_elements = sum(divmod(row_length, 2)) + row_first_half = [ + temp_row[i - 1] + temp_row[i] for i in range(1, distinct_elements + 1) + ] + row_second_half = row_first_half[: (row_index + 1) // 2] + row_second_half.reverse() + row = row_first_half + row_second_half + result.append(row) + + return result + + +def benchmark() -> None: + """ + Benchmark multiple functions, with three different length int values. + """ + from collections.abc import Callable + from timeit import timeit + + def benchmark_a_function(func: Callable, value: int) -> None: + call = f"{func.__name__}({value})" + timing = timeit(f"__main__.{call}", setup="import __main__") + # print(f"{call:38} = {func(value)} -- {timing:.4f} seconds") + print(f"{call:38} -- {timing:.4f} seconds") + + for value in range(15): # (1, 7, 14): + for func in (generate_pascal_triangle, generate_pascal_triangle_optimized): + benchmark_a_function(func, value) + print() + + if __name__ == "__main__": import doctest doctest.testmod() + benchmark()