To Lower Case
文字列 s が与えられます。すべての英大文字(A から Z)を対応する小文字に置き換えた新しい文字列を返してください。小文字、数字、記号など、それ以外の文字はすべてそのままにします。
関数
- sstring
- 変換するテキスト
- 戻り値string
- すべての大文字を小文字にした s
制約
1 ≤ s.length ≤ 104-
sの各文字は、英字、数字、または次の記号のいずれかです:!#$%&()*+-./:;<=>?@[]^_`{|}~。
例
- 入力
- s = "Hello-World!"
- 出力
- "hello-world!"
- 説明
- 大文字の
HとWはhとwになります。-と!は文字ではないため、そのままの位置に残ります。
- 入力
- s = "coddy_2026"
- 出力
- "coddy_2026"
- 説明
- 変更する大文字はありません。小文字、
_、数字はそのまま戻ります。
- 入力
- s = "SQL"
- 出力
- "sql"
- 説明
- 3つの文字はすべて大文字なので、それぞれ小文字に変換されます。
提出時に隠しテスト+15件
発展問題
toUpperCaseを同じループで書き、文字コードの1ビットだけがAとaの違いである理由を説明できますか?
ヒント
1つずつ開いてください。開くたびに少しずつ答えに近づきます。
コンピューターは各文字を数値として保存します。
Aとaの数値にはどのような関係があるでしょうか?AからZまではコード65から90で、aからzまでは97から122です。それぞれの大文字は、対応する小文字よりちょうど32小さい値です。文字を1つずつ処理します。コードが65から90の間にある場合は32を加え、それ以外の場合は文字をそのままにします。結果を集めて結合し、答えにします。
解説
どの言語にも小文字に変換する関数が用意されており、実際のコードではそれを呼び出すべきです。面接官がこの問題を出すのは、その関数の動作を理解しているかを確認するためです。文字は数値であり、ASCIIでは各大文字のコードは対応する小文字よりちょうど32小さくなっています。コードが 'A' と 'Z' の間にあるかどうかを確認し、当てはまる場合は32を加えます。
組み込みの小文字化関数を呼び出す
考え方
Python の lower()、JavaScript の toLowerCase()、Ruby の downcaseや、ほかのすべての言語にある同様の関数は、すでにこの処理を行います。C と C++ には1文字を対象とする tolower があるので、ループ内で呼び出します。各文字を一度ずつ調べるため、処理量は O(n) で、新しい文字列に必要な領域は O(n) です。
これらの関数の中には、マシンの言語設定に従うものもあります。トルコ語では、I の小文字は点のない ı であり、i ではありません。そのため、Java と C# のバージョンでは Locale.ROOT と ToLowerInvariant を使って固定のルールを指定し、コンピューターによって結果が変わらないようにします。
実務ではこれが正しい答えです。面接では、問題の要点となるアイデアが隠れてしまうため、受け入れられないことがよくあります。
アルゴリズム
- 言語の小文字変換関数を
sに対して呼び出すか、CおよびC++では各文字に対してtolowerを呼び出します。 - 関数で指定できる場合は、言語に依存しない固定の規則を指定します。
- 結果を返します。
def toLowerCase(s):
return s.lower()大文字の文字コードをシフトする
考え方
すべての文字は数値として格納されます。ASCIIでは、AからZまでのコードは65から90で、aからzまでは97から122です。どちらもアルファベット順に並び、その開始位置は32離れているため、任意の大文字の小文字は、そのコードに32を加えたものです。Hは72で、hは104です。
そこで、文字列を一度だけ順に見ていきます。コードが65から90の範囲内なら32を加え、それ以外なら文字をそのままコピーします。範囲の確認は重要です。記号[、^、_はZとaの間にあり、@はAのすぐ前にあります。code < 97だけを調べると、_が別の記号に変わってしまいます。
各文字を一度ずつ確認するため、時間計算量はO(n)です。答えは元の文字列と同じ長さの新しい文字列なので、空間計算量はO(n)です。32の代わりに'a' - 'A'と書けば、同じ意味を表し、その数値の由来もわかります。
アルゴリズム
sを文字またはコードの配列にコピーします。- 各位置について、文字コードを読み取ります。
- コードが
'A'(65)から'Z'(90)の間にある場合は、32を加えます。 - 配列を文字列に戻して返します。
def toLowerCase(s):
# Every capital letter sits 32 codes below its small letter: 'A' is 65, 'a' is 97.
shift = ord("a") - ord("A")
chars = []
for ch in s:
if "A" <= ch <= "Z":
ch = chr(ord(ch) + shift)
chars.append(ch)
return "".join(chars)
落とし穴と境界ケース
ループは短いため、間違いは範囲チェックと答えの組み立て方にあります。
- 小文字ではないすべての文字に32を加えること。数字や記号も変わってしまいます。
1はQになります。 - 範囲の片端だけをチェックすること。
code < 'a'は[、_、@にも当てはまり、code >= 'A'はすべての小文字にも当てはまります。 - 範囲の端で
<=ではなく<を使うと、AまたはZが大文字のままになります。 - 変更不可能な文字列に対して
result = result + chで答えを組み立てること。各ステップでそれまでの内容すべてがコピーされるため、n = 10^4では計算量が二次になります。 - Cでは、入力を書き換えたり、終端の
'\0'を忘れたりすること。コピー用にn + 1バイトを確保してください。
よくある質問4
組み込み関数を使わずに、文字列を小文字に変換するにはどうすればよいですか?
文字を順に処理し、それぞれの文字コードを確認します。コードが 65(A)から 90(Z)の間であれば、32 を加えて小文字にします。それ以外の文字はそのままにします。文字を結合して文字列に戻します。
大文字と小文字の違いが32なのはなぜですか?
ASCIIでは、大文字はコード65〜90、小文字は97〜122に配置され、その間には6つの記号があります。どちらのアルファベットも同じ順序なので、各ペアの差は97 - 65 = 32です。32は1ビットなので、そのビットを立てると大文字が小文字に変わります。
ビット演算で大文字と小文字を変換できますか?
はい。大文字の場合、code | 32は大文字と小文字を区別するビットをセットして小文字にし、code & ~32はそのビットを再びクリアします。同じビット操作で数字や記号も変わってしまうため、最初に範囲チェックを行う必要があります。
文字列を小文字に変換する場合の時間計算量はどれくらいですか?
長さnの文字列の場合、各文字を1回ずつ確認するため、O(n)です。新しい文字列にはO(n)の領域が必要です。文字配列をその場で変更できる場合、追加領域はO(1)になります。
似た問題
同じ考え方を使う問題です。2〜3問解くとパターンが身につきます。
Python
def toLowerCase(s):
# ここにコードを書いてくださいケース1
ケース2
ケース3
入力
s = "Hello-World!"
期待値
"hello-world!"