Can String Be Rearranged as Palindrome

# Created by susmith98

from collections import Counter
from timeit import timeit

# Problem Description:
# Check if characters of the given string can be rearranged to form a palindrome.
# Counter is faster for long strings and non-Counter is faster for short strings.


def can_string_be_rearranged_as_palindrome_counter(
    input_str: str = "",
) -> bool:
    """
    A Palindrome is a String that reads the same forward as it does backwards.
    Examples of Palindromes mom, dad, malayalam
    >>> can_string_be_rearranged_as_palindrome_counter("Momo")
    True
    >>> can_string_be_rearranged_as_palindrome_counter("Mother")
    False
    >>> can_string_be_rearranged_as_palindrome_counter("Father")
    False
    >>> can_string_be_rearranged_as_palindrome_counter("A man a plan a canal Panama")
    True
    """
    return sum(c % 2 for c in Counter(input_str.replace(" ", "").lower()).values()) < 2


def can_string_be_rearranged_as_palindrome(input_str: str = "") -> bool:
    """
    A Palindrome is a String that reads the same forward as it does backwards.
    Examples of Palindromes mom, dad, malayalam
    >>> can_string_be_rearranged_as_palindrome("Momo")
    True
    >>> can_string_be_rearranged_as_palindrome("Mother")
    False
    >>> can_string_be_rearranged_as_palindrome("Father")
    False
    >>> can_string_be_rearranged_as_palindrome_counter("A man a plan a canal Panama")
    True
    """
    if len(input_str) == 0:
        return True
    lower_case_input_str = input_str.replace(" ", "").lower()
    # character_freq_dict: Stores the frequency of every character in the input string
    character_freq_dict: dict[str, int] = {}

    for character in lower_case_input_str:
        character_freq_dict[character] = character_freq_dict.get(character, 0) + 1
    """
    Above line of code is equivalent to:
    1) Getting the frequency of current character till previous index
    >>> character_freq =  character_freq_dict.get(character, 0)
    2) Incrementing the frequency of current character by 1
    >>> character_freq = character_freq + 1
    3) Updating the frequency of current character
    >>> character_freq_dict[character] = character_freq
    """
    """
    OBSERVATIONS:
    Even length palindrome
    -> Every character appears even no.of times.
    Odd length palindrome
    -> Every character appears even no.of times except for one character.
    LOGIC:
    Step 1: We'll count number of characters that appear odd number of times i.e oddChar
    Step 2:If we find more than 1 character that appears odd number of times,
    It is not possible to rearrange as a palindrome
    """
    oddChar = 0

    for character_count in character_freq_dict.values():
        if character_count % 2:
            oddChar += 1
    if oddChar > 1:
        return False
    return True


def benchmark(input_str: str = "") -> None:
    """
    Benchmark code for comparing above 2 functions
    """
    print("\nFor string = ", input_str, ":")
    print(
        "> can_string_be_rearranged_as_palindrome_counter()",
        "\tans =",
        can_string_be_rearranged_as_palindrome_counter(input_str),
        "\ttime =",
        timeit(
            "z.can_string_be_rearranged_as_palindrome_counter(z.check_str)",
            setup="import __main__ as z",
        ),
        "seconds",
    )
    print(
        "> can_string_be_rearranged_as_palindrome()",
        "\tans =",
        can_string_be_rearranged_as_palindrome(input_str),
        "\ttime =",
        timeit(
            "z.can_string_be_rearranged_as_palindrome(z.check_str)",
            setup="import __main__ as z",
        ),
        "seconds",
    )


if __name__ == "__main__":
    check_str = input(
        "Enter string to determine if it can be rearranged as a palindrome or not: "
    ).strip()
    benchmark(check_str)
    status = can_string_be_rearranged_as_palindrome_counter(check_str)
    print(f"{check_str} can {'' if status else 'not '}be rearranged as a palindrome")
Algerlogo

Β© Alger 2022

About us

We are a group of programmers helping each other build new things, whether it be writing complex encryption programs, or simple ciphers. Our goal is to work together to document and model beautiful, helpful and interesting algorithms using code. We are an open-source community - anyone can contribute. We check each other's work, communicate and collaborate to solve problems. We strive to be welcoming, respectful, yet make sure that our code follows the latest programming guidelines.