Skip to content

LeetCode 709: To Lower Case

A clear explanation of converting uppercase ASCII letters to lowercase by scanning the string once.

Problem Restatement

We are given a string s.

Return a new string after replacing every uppercase letter with the same lowercase letter.

All other characters stay unchanged.

The string consists of printable ASCII characters.

Input and Output

ItemMeaning
InputA string s
OutputThe same string with uppercase letters converted to lowercase
Constraint1 <= s.length <= 100
CharactersPrintable ASCII characters

The function shape is:

class Solution:
    def toLowerCase(self, s: str) -> str:
        ...

Examples

Example 1:

s = "Hello"

The uppercase letter H becomes h.

Output:

"hello"

Example 2:

s = "here"

There are no uppercase letters.

Output:

"here"

Example 3:

s = "LOVELY"

Every letter is uppercase.

Output:

"lovely"

First Thought: Use the Built-in Method

Python already has a method for this:

s.lower()

So the shortest accepted solution is:

class Solution:
    def toLowerCase(self, s: str) -> str:
        return s.lower()

This is correct and simple.

But this problem is often used to practice character handling, so we can also implement the conversion manually.

Key Insight

In ASCII, uppercase letters have consecutive codes:

'A' -> 65
'B' -> 66
...
'Z' -> 90

Lowercase letters also have consecutive codes:

'a' -> 97
'b' -> 98
...
'z' -> 122

The difference between matching uppercase and lowercase letters is always:

ord('a') - ord('A') == 32

So if a character ch is between 'A' and 'Z', its lowercase version is:

chr(ord(ch) + 32)

Characters outside that uppercase range should be copied unchanged.

Algorithm

Create an empty list result.

For each character ch in s:

  1. If ch is between 'A' and 'Z', convert it to lowercase by adding 32 to its ASCII code.
  2. Otherwise, keep ch unchanged.
  3. Append the resulting character to result.

At the end, join the list into a string.

Correctness

The algorithm examines every character of s.

If a character is an uppercase ASCII letter, then it lies between 'A' and 'Z'. Adding 32 to its ASCII value gives the matching lowercase letter. Therefore the algorithm converts every uppercase letter correctly.

If a character is not an uppercase ASCII letter, the algorithm appends it unchanged. Therefore lowercase letters, digits, spaces, and punctuation are preserved.

Since every character is processed exactly once and appended in the original order, the returned string is exactly s with uppercase letters replaced by their lowercase versions.

Complexity

Let n be the length of s.

MetricValueWhy
TimeO(n)We scan every character once
SpaceO(n)We build a result string of length n

Implementation

class Solution:
    def toLowerCase(self, s: str) -> str:
        result = []

        for ch in s:
            if "A" <= ch <= "Z":
                result.append(chr(ord(ch) + 32))
            else:
                result.append(ch)

        return "".join(result)

Code Explanation

We use a list because strings are immutable in Python:

result = []

For each character, check whether it is uppercase ASCII:

if "A" <= ch <= "Z":

If so, convert it:

result.append(chr(ord(ch) + 32))

If not, keep it unchanged:

else:
    result.append(ch)

Finally, join all characters into the answer:

return "".join(result)

Alternative: Bit Operation

ASCII uppercase and lowercase letters differ by one bit.

So another manual conversion is:

class Solution:
    def toLowerCase(self, s: str) -> str:
        result = []

        for ch in s:
            if "A" <= ch <= "Z":
                result.append(chr(ord(ch) | 32))
            else:
                result.append(ch)

        return "".join(result)

This works because ord(ch) | 32 sets the lowercase bit for uppercase ASCII letters.

The range check is still important. Without it, applying | 32 to punctuation or other characters can change them incorrectly.

Testing

def test_to_lower_case():
    s = Solution()

    assert s.toLowerCase("Hello") == "hello"
    assert s.toLowerCase("here") == "here"
    assert s.toLowerCase("LOVELY") == "lovely"
    assert s.toLowerCase("A1B2C3") == "a1b2c3"
    assert s.toLowerCase("Python-3.12!") == "python-3.12!"
    assert s.toLowerCase("already lower") == "already lower"

    print("all tests passed")

test_to_lower_case()

Test coverage:

TestWhy
Mixed caseConfirms partial conversion
Already lowercaseConfirms unchanged letters
All uppercaseConfirms full conversion
DigitsConfirms nonletters stay unchanged
PunctuationConfirms printable ASCII characters are preserved