🅰️

JavaScriptで解くLeetCode:String to Integer (atoi)

2024/12/31に公開

このシリーズでは、プログラミング学習サイト LeetCode に掲載されている問題の中から良問を厳選し、JavaScript を使って解説していきます。

今回は、Arai60に収録されている「String to Integer (atoi)」の問題を、JavaScriptでどのように実装するか解説します。

C言語の標準関数「atoi」をモデルにした問題ですが、実装上のポイントが多数あり、よい練習問題となっています。

以下のサイトから問題に挑戦できます。
https://leetcode.com/problems/string-to-integer-atoi

問題の概要

与えられた文字列 s を解析し、次のルールに従って 32ビット符号付き整数に変換する関数 myAtoi を実装します。詳細は以下のとおりです。

  1. 空白の無視
    入力文字列の先頭にある空白(スペース文字など)をすべて無視します。

  2. 符号の判定
    次の文字が + または - であれば、読み取り対象とし、正負を記憶します。
    それ以外の場合は、符号はプラスであると仮定します。

  3. 数字の読み取り
    次に連続する数字(0〜9)を読み取ります。数字以外の文字が現れた時点で読み取りを停止します。

  4. 範囲の丸め
    32ビット符号付き整数の範囲である [-2^31, 2^31 - 1] を超えた場合は、下限または上限で丸めます。

  5. 結果を返す
    最終的な数値を返します。

制約

  • 0 <= s.length <= 200
  • 文字列 s は英字、数字、空白、+, -, . などを含む場合があります。

実装コード

以下が JavaScript での実装例です。

/**
 * @param {string} s
 * @return {number}
 */
var myAtoi = function(s) {
    // 1. 先頭の空白を除去
    s = s.trim();

    // 2. 空文字列のチェック
    if (s.length === 0) return 0;

    // 3. 符号判定
    let sign = 1;
    let index = 0;
    if (s[0] === '-') {
        sign = -1;
        index++;
    } else if (s[0] === '+') {
        index++;
    }

    // 4. 数字を読み取る
    let result = 0;
    while (index < s.length && s[index] >= '0' && s[index] <= '9') {
        result = result * 10 + (s[index] - '0');
        index++;
    }

    // 5. 符号を適用
    result *= sign;

    // 6. 範囲の制限
    const INT_MIN = -(2 ** 31);
    const INT_MAX = 2 ** 31 - 1;
    if (result < INT_MIN) return INT_MIN;
    if (result > INT_MAX) return INT_MAX;

    // 7. 結果を返す
    return result;
};

ステップごとの解説

1. 先頭の空白を除去

s = s.trim();
  • trim() を使うことで、文字列の先頭と末尾の空白を一括で削除できます。
  • 例: " -42""-42"

2. 空文字列のチェック

if (s.length === 0) return 0;
  • トリミング後に空文字列になった場合は変換できないため、そのまま 0 を返します。

3. 符号判定

let sign = 1;
let index = 0;
if (s[0] === '-') {
    sign = -1;
    index++;
} else if (s[0] === '+') {
    index++;
}
  • 最初の文字が - の場合は sign = -1+ の場合は sign = 1 として記憶します。
  • 符号文字を検知したら、次の文字へ進めるため index++ を行います。

4. 数字を読み取る

let result = 0;
while (index < s.length && s[index] >= '0' && s[index] <= '9') {
    result = result * 10 + (s[index] - '0');
    index++;
}
  • 数字以外の文字が出るまで繰り返し、 result を更新し続けます。
  • 一文字ずつ charCode を足し込む形にすることで、連続する数字を一括で整数に変換します。

5. 符号を適用

result *= sign;
  • sign の値が -1 の場合は result を負の値にします。

6. 範囲の制限

const INT_MIN = -(2 ** 31);
const INT_MAX = 2 ** 31 - 1;
if (result < INT_MIN) return INT_MIN;
if (result > INT_MAX) return INT_MAX;
  • 32 ビット符号付き整数の範囲を逸脱した場合は、下限または上限にクリップ(丸め)します。

7. 結果を返す

return result;
  • 上記の処理を終えた最終的な数値を返します。

実行例

入力 出力 説明
"42" 42 純粋に数字なのでそのまま変換
" -42" -42 先頭の空白を削除し、符号 - により負数へ
"1337c0d3" 1337 数字以外の文字が出現した時点で変換を終了
"0-1" 0 0 を読んだあと - に遭遇するため、数字のみ変換
"words and 987" 0 先頭がアルファベットのため、数字なし→ 0 を返す

まとめ

  • 文字列解析: 先頭空白の削除、符号チェック、数字読み取りといった処理が段階的に行われる。
  • 境界値対策: 32 ビット整数範囲を超えた場合は上限・下限にクリップする。
  • 実装ポイント: trim()charCode による判定など、JavaScript の組み込みメソッドを活用するとスッキリ書ける。

この問題は、文字列処理から整数変換までの一連の流れをしっかり理解するのに適した練習問題です。

See you later alligator.

Discussion