# Problem Description:
The task is to find the largest rectangle submatrix within a given 2D list (matrix) of characters that consists entirely of the same character. The function should return the area of this largest rectangle. Each cell in the matrix contributes an area of 1.

# Visual Facts:
1. **Invalid Patterns**:
   - The first invalid pattern shows a highlighted area that is not a rectangle.
   - The second invalid pattern shows a highlighted area that contains different characters.
   - The third invalid pattern shows a highlighted area that is not the maximum possible rectangle for the character 'B'.

2. **Valid Patterns**:
   - The first valid pattern has a maximum rectangle area of 4.
   - The second valid pattern has a maximum rectangle area of 9.
   - The third valid pattern has a maximum rectangle area of 20.
   - The fourth valid pattern has a maximum rectangle area of 24.

# Visual Patterns:
1. **Rectangle Shape**:
   - The highlighted area must form a perfect rectangle.

2. **Uniform Character**:
   - The highlighted rectangle must consist of the same character throughout.

3. **Maximum Area**:
   - The highlighted rectangle must be the largest possible rectangle for that character within the given matrix.

4. **Calculation of Area**:
   - The area of the rectangle is calculated by multiplying the number of rows by the number of columns in the rectangle.

5. **Matrix Constraints**:
   - The matrix can contain various characters, and the function must identify the largest rectangle for any character present.



# Solution
from typing import List

def solution(matrix: List[List[str]]) -> int:
    """
    Calculates the max area of the matrix according to illustrated rules.

    Args:
        matrix: A 2D list containing characters.

    Returns:
        The max area of the matrix
    """
    if not matrix or not matrix[0]:
        return 0

    rows = len(matrix)
    cols = len(matrix[0])
    
    # Initialize a DP table to store the height of consecutive same elements
    dp = [[0] * cols for _ in range(rows)]
    
    max_area = 0  # To store the maximum area found

    for i in range(rows):
        for j in range(cols):
            if i == 0:
                # First row: height is 1 if the element is the same as the one above
                dp[i][j] = 1
            else:
                # If the current element is the same as the one above, increment the height
                if matrix[i][j] == matrix[i - 1][j]:
                    dp[i][j] = dp[i - 1][j] + 1
                else:
                    dp[i][j] = 1

            # Now, find the maximum rectangle area ending at (i, j)
            min_height = dp[i][j]
            for k in range(j, -1, -1):
                if matrix[i][k] != matrix[i][j]:
                    break  # Stop if the elements are not the same
                min_height = min(min_height, dp[i][k])
                width = j - k + 1
                area = width * min_height
                if area > max_area:
                    max_area = area

    return max_area


# Test Script
def test():
    test_cases = [
        (
            [['A']],
            1
        ),
        (
            [['A','A'],
             ['A','A']],
            4
        ),
        (
            [['A','B'],
             ['C','D']],
            1
        ),
        (
            [['A','A','B'],
             ['A','A','A']],
            4
        ),
        (
            [['B','B','B','B'],
             ['B','B','B','B'],
             ['B','B','B','B']],
            12
        ),
        (
            [['A','B','C'],
             ['D','E','F'],
             ['G','H','I']],
            1
        ),
        (
            [['A','A','A','B'],
             ['A','A','A','B'],
             ['A','A','A','B'],
             ['C','C','C','C']],
            9
        ),
        (
            [['A','C','A'],
             ['A','B','B'],
             ['A','B','B']],
            4
        ),
        (
            [['A','A','A','A'],
             ['A','A','A','A'],
             ['A','A','A','A'],
             ['A','A','A','A']],
            16
        ),
        (
            [['A','A','A','A','A'],
             ['A','A','A','A','A'],
             ['A','A','A','A','A'],
             ['A','A','A','A','A'],
             ['A','A','A','A','A']],
            25
        ),
    ]

    for matrix, expected_output in test_cases:
        try:
            output = solution(matrix)
        except Exception as e:
            error_message = (
                f"An exception occurred while running the test case:\n"
                f"`matrix`: [\n"
            )
            for row in matrix:
                error_message += f"    {row}\n"
            error_message += "]\n\n"
            error_message += f"Exception: '{str(e)}'"
            assert False, error_message

        if output != expected_output:
            error_message = (
                f"The following Test Case failed:\n"
                f"`matrix`: [\n"
            )
            for row in matrix:
                error_message += f"    {row}\n"
            error_message += "]\n\n"
            error_message += f"Actual Output: {output}\n"
            error_message += f"Expected Output: {expected_output}"
            assert False, error_message

test()