From 5b5c1cc840411339d3b5559359aaa2bc6a576de5 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Mon, 22 Sep 2025 00:01:11 +0900 Subject: [PATCH 1/6] Solve 8_string_to_integer_atoi_medium --- 8_string_to_integer_atoi_medium/README.md | 152 ++++++++++++++++++++++ 8_string_to_integer_atoi_medium/step1.py | 54 ++++++++ 8_string_to_integer_atoi_medium/step2.py | 46 +++++++ 3 files changed, 252 insertions(+) create mode 100644 8_string_to_integer_atoi_medium/README.md create mode 100644 8_string_to_integer_atoi_medium/step1.py create mode 100644 8_string_to_integer_atoi_medium/step2.py diff --git a/8_string_to_integer_atoi_medium/README.md b/8_string_to_integer_atoi_medium/README.md new file mode 100644 index 0000000..e4feabb --- /dev/null +++ b/8_string_to_integer_atoi_medium/README.md @@ -0,0 +1,152 @@ +# 問題へのリンク +[8. String to Integer (atoi)](https://leetcode.com/problems/string-to-integer-atoi/) + +# 言語 +Python + + +# 自分の解法 +dislikesが多いのは、LeetCodeらしからぬ細かい仕様が多いから? +## step1 + +```python +class Solution: + CHAR_TO_DIGIT = {str(i): i for i in range(10)} + + def myAtoi(self, s: str) -> int: + SPACE = " " + PLUS = "+" + MINUS = "-" + MIN = -(2**31) + MAX = 2**31 - 1 + if not s: + return 0 + num = 0 + # remove leading whitespaces + i = 0 + while i < len(s) and s[i] == SPACE: + i += 1 + s = s[i:] + if not s: + return 0 + # process sign + is_negative = False + if s[0] == PLUS: + s = s[1:] + elif s[0] == MINUS: + s = s[1:] + is_negative = True + if not s: + return 0 + # conversion + digits: list[int] = [] + for char in s: + if char not in self.CHAR_TO_DIGIT: + break + digit = self.CHAR_TO_DIGIT[char] + digits.append(digit) + digits.reverse() + for i, digit in enumerate(digits): + num += digit * pow(10, i) + num = -num if is_negative else num + # rounding + num = min(num, MAX) + num = max(num, MIN) + + return num +``` +- leading whitespace を取り除く箇所で何度かミスってしまった + - まず`s.replace(" ", "")`で全ての空白を取り除いてしまっていた + - 次に前から空白を取り除く処理を実装したが、何度かバグを踏んだ + - `while i < len(s) and ...`と先にandしておくと、`i`が`len(s)`に達したときに`s[i]`でIndexErrorになる問題を防げる + +- 時間計算量:`O(n)` +- 空間計算量:`O(n)` + +## step2 + +```python +class Solution: + CHAR_TO_DIGIT = {str(i): i for i in range(10)} + def myAtoi(self, s: str) -> int: + SPACE = " " + PLUS = "+" + MINUS = "-" + MIN_INT = -(2**31) + MAX_INT = 2**31 - 1 + if not s: + return 0 + num = 0 + + # remove leading whitespaces + i = 0 + while i < len(s) and s[i] == SPACE: + i += 1 + # process sign + sign = 1 + if i < len(s) and s[i] == PLUS: + i += 1 + elif i < len(s) and s[i] == MINUS: + i += 1 + sign = -1 + # conversion + while i < len(s) and s[i] in self.CHAR_TO_DIGIT: + digit = self.CHAR_TO_DIGIT[s[i]] + num = num * 10 + digit + i += 1 + num = sign * num + # rounding + num = min(num, MAX_INT) + num = max(num, MIN_INT) + + return num +``` + + +- 文字列のスライスを使わないようにした。これにより、`O(n)`の時間計算量と`O(1)`の空間計算量で実装できる +- `is_negative`を`sign`に変更した + - `sign`を`1`か`-1`にしておくと、最後に`num=sign*num`とするだけで済む + + +最後の変換部分のロジックを +```python +digits.reverse() +for i, digit in enumerate(digits): + num += digit * pow(10, i) +``` +から +```python +for digit in digits: + num = num * 10 + digit +``` +と書き換えた +- `digits`を逆順にする必要がなくなった +- `pow`を使わなくなった +- `num=0`から始めて、`num=num*10+digit`を繰り返すことで、上の位の桁から順に処理できる + +- > `ord(s[pos]) - ord('0')`の代わりに`int(s[pos])`とかも選択肢としてあり。とはいえこれをするんだったら`int(s[index:])`みたいにやっていいじゃんという気持ちにもなるので、この問題的にはint使わない方が空気が読めてそう。 +- `ord`を使う方法もある +(ref: https://github.com/hayashi-ay/leetcode/pull/69/files) +- `is_digit`メソッドについて調べる + +## step3 + +## step4 (FB) + + + +# 別解・模範解答 + +- 時間計算量:`O(n)` +- 空間計算量:`O(n)` + +# 想定されるフォローアップ質問 + +## CS 基礎 + +## システム設計 + +## その他 + +# 次に解く問題の予告 +- Permutations diff --git a/8_string_to_integer_atoi_medium/step1.py b/8_string_to_integer_atoi_medium/step1.py new file mode 100644 index 0000000..14d5fb4 --- /dev/null +++ b/8_string_to_integer_atoi_medium/step1.py @@ -0,0 +1,54 @@ +# +# @lc app=leetcode id=8 lang=python3 +# +# [8] String to Integer (atoi) +# + +# @lc code=start +class Solution: + CHAR_TO_DIGIT = {str(i): i for i in range(10)} + + def myAtoi(self, s: str) -> int: + SPACE = " " + PLUS = "+" + MINUS = "-" + MIN = -(2**31) + MAX = 2**31 - 1 + if not s: + return 0 + num = 0 + # remove leading whitespaces + i = 0 + while i < len(s) and s[i] == SPACE: + i += 1 + s = s[i:] + if not s: + return 0 + # process sign + is_negative = False + if s[0] == PLUS: + s = s[1:] + elif s[0] == MINUS: + s = s[1:] + is_negative = True + if not s: + return 0 + # conversion + digits: list[int] = [] + for char in s: + if char not in self.CHAR_TO_DIGIT: + break + digit = self.CHAR_TO_DIGIT[char] + digits.append(digit) + digits.reverse() + for i, digit in enumerate(digits): + num += digit * pow(10, i) + num = -num if is_negative else num + # rounding + num = min(num, MAX) + num = max(num, MIN) + + return num + + +# @lc code=end diff --git a/8_string_to_integer_atoi_medium/step2.py b/8_string_to_integer_atoi_medium/step2.py new file mode 100644 index 0000000..840081d --- /dev/null +++ b/8_string_to_integer_atoi_medium/step2.py @@ -0,0 +1,46 @@ +# +# @lc app=leetcode id=8 lang=python3 +# +# [8] String to Integer (atoi) +# + +# @lc code=start +class Solution: + CHAR_TO_DIGIT = {str(i): i for i in range(10)} + + def myAtoi(self, s: str) -> int: + SPACE = " " + PLUS = "+" + MINUS = "-" + MIN_INT = -(2**31) + MAX_INT = 2**31 - 1 + + if not s: + return 0 + num = 0 + + # remove leading whitespaces + i = 0 + while i < len(s) and s[i] == SPACE: + i += 1 + # process sign + sign = 1 + if i < len(s) and s[i] == PLUS: + i += 1 + elif i < len(s) and s[i] == MINUS: + sign = -1 + i += 1 + # conversion + while i < len(s) and s[i] in self.CHAR_TO_DIGIT: + digit = self.CHAR_TO_DIGIT[s[i]] + num = num * 10 + digit + i += 1 + num = sign * num + # rounding + num = min(num, MAX_INT) + num = max(num, MIN_INT) + + return num + + +# @lc code=end From 15b5b5b857e4967962056ca657987ffc2d4cf684 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Mon, 22 Sep 2025 00:01:20 +0900 Subject: [PATCH 2/6] Add step3 file (no implementations) --- 8_string_to_integer_atoi_medium/step3.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 8_string_to_integer_atoi_medium/step3.py diff --git a/8_string_to_integer_atoi_medium/step3.py b/8_string_to_integer_atoi_medium/step3.py new file mode 100644 index 0000000..24ab7a1 --- /dev/null +++ b/8_string_to_integer_atoi_medium/step3.py @@ -0,0 +1,13 @@ +# +# @lc app=leetcode id=8 lang=python3 +# +# [8] String to Integer (atoi) +# + +# @lc code=start +class Solution: + def myAtoi(self, s: str) -> int: + return 0 + + +# @lc code=end From ed8eca49b087e4a799f02391e167b766934d971e Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 9 Nov 2025 17:25:23 +0900 Subject: [PATCH 3/6] Update step2 --- 8_string_to_integer_atoi_medium/README.md | 49 +++++++++++++++++------ 8_string_to_integer_atoi_medium/step2.py | 23 +++++------ 2 files changed, 48 insertions(+), 24 deletions(-) diff --git a/8_string_to_integer_atoi_medium/README.md b/8_string_to_integer_atoi_medium/README.md index e4feabb..8a03600 100644 --- a/8_string_to_integer_atoi_medium/README.md +++ b/8_string_to_integer_atoi_medium/README.md @@ -63,37 +63,61 @@ class Solution: - 時間計算量:`O(n)` - 空間計算量:`O(n)` +Tests +- standard cases: + - `s=" 00321a3"` -> 321 + - `s=" +00321a3"` -> 321 + - `s=" -00321a3"` -> -321 +- empty: + - `s=""` -> 0 +- invalid cases: + - `s=" "` -> 0 + - `s="a"` -> 0 + - `s="a1"` -> 0 +- whitespaces: + - `s=" 1"` -> 1 +- signedness: + - `s="1"` -> 1 + - `s="+1"` -> 1 + - `s="-1"` -> -1 +- leading zeros: + - `s="0010"` -> 10 +- rounded cases: + - `s="-1_000_000_000_000"` -> -2**31 + - `s="1_000_000_000_000"` -> 2**31-1 + ## step2 ```python class Solution: - CHAR_TO_DIGIT = {str(i): i for i in range(10)} def myAtoi(self, s: str) -> int: SPACE = " " PLUS = "+" MINUS = "-" MIN_INT = -(2**31) MAX_INT = 2**31 - 1 + if not s: return 0 num = 0 # remove leading whitespaces - i = 0 - while i < len(s) and s[i] == SPACE: - i += 1 + index = 0 + while index < len(s) and s[index] == SPACE: + index += 1 # process sign sign = 1 - if i < len(s) and s[i] == PLUS: - i += 1 - elif i < len(s) and s[i] == MINUS: - i += 1 + if index < len(s) and s[index] == PLUS: + index += 1 + elif index < len(s) and s[index] == MINUS: sign = -1 + index += 1 # conversion - while i < len(s) and s[i] in self.CHAR_TO_DIGIT: - digit = self.CHAR_TO_DIGIT[s[i]] + while index < len(s) and "0"<=s[index]<="9": + digit = ord(s[index]) - ord("0") num = num * 10 + digit - i += 1 + index += 1 + num = sign * num # rounding num = min(num, MAX_INT) @@ -127,7 +151,8 @@ for digit in digits: - > `ord(s[pos]) - ord('0')`の代わりに`int(s[pos])`とかも選択肢としてあり。とはいえこれをするんだったら`int(s[index:])`みたいにやっていいじゃんという気持ちにもなるので、この問題的にはint使わない方が空気が読めてそう。 - `ord`を使う方法もある (ref: https://github.com/hayashi-ay/leetcode/pull/69/files) -- `is_digit`メソッドについて調べる + - Pythonでは文字列にも比較演算子が使えるので、`"0" <= s[i] <= "9"`のようにするのが良いかも +- `is_digit`メソッドはASCIIコード以外にも対応したメソッドなので、今回は使わなくて良い ## step3 diff --git a/8_string_to_integer_atoi_medium/step2.py b/8_string_to_integer_atoi_medium/step2.py index 840081d..b055ae4 100644 --- a/8_string_to_integer_atoi_medium/step2.py +++ b/8_string_to_integer_atoi_medium/step2.py @@ -6,8 +6,6 @@ # @lc code=start class Solution: - CHAR_TO_DIGIT = {str(i): i for i in range(10)} - def myAtoi(self, s: str) -> int: SPACE = " " PLUS = "+" @@ -20,21 +18,22 @@ def myAtoi(self, s: str) -> int: num = 0 # remove leading whitespaces - i = 0 - while i < len(s) and s[i] == SPACE: - i += 1 + index = 0 + while index < len(s) and s[index] == SPACE: + index += 1 # process sign sign = 1 - if i < len(s) and s[i] == PLUS: - i += 1 - elif i < len(s) and s[i] == MINUS: + if index < len(s) and s[index] == PLUS: + index += 1 + elif index < len(s) and s[index] == MINUS: sign = -1 - i += 1 + index += 1 # conversion - while i < len(s) and s[i] in self.CHAR_TO_DIGIT: - digit = self.CHAR_TO_DIGIT[s[i]] + while index < len(s) and "0"<=s[index]<="9": + digit = ord(s[index]) - ord("0") num = num * 10 + digit - i += 1 + index += 1 + num = sign * num # rounding num = min(num, MAX_INT) From 0a5c6e8079fc8934ddc5d154bfd4222a668e4dd7 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 9 Nov 2025 17:26:39 +0900 Subject: [PATCH 4/6] Add step3 --- 8_string_to_integer_atoi_medium/README.md | 46 +++++++++++++++++++++++ 8_string_to_integer_atoi_medium/step3.py | 40 +++++++++++++++++++- 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/8_string_to_integer_atoi_medium/README.md b/8_string_to_integer_atoi_medium/README.md index 8a03600..6c81d7e 100644 --- a/8_string_to_integer_atoi_medium/README.md +++ b/8_string_to_integer_atoi_medium/README.md @@ -155,6 +155,52 @@ for digit in digits: - `is_digit`メソッドはASCIIコード以外にも対応したメソッドなので、今回は使わなくて良い ## step3 +```python +class Solution: + def myAtoi(self, s: str) -> int: + if not s: + return 0 + index = 0 + # Process whitespace + SPACE = " " + while index < len(s) and s[index] == SPACE: + index += 1 + + # Process signedness + is_negative = False + MINUS = "-" + PLUS = "+" + if index < len(s) and s[index] == MINUS: + is_negative = True + index += 1 + elif index < len(s) and s[index] == PLUS: + index += 1 + + # Process conversion + num = 0 + # leading zeros + while index < len(s) and s[index] == str(0): + index += 1 + digits = [str(i) for i in range(10)] + while index < len(s) and s[index] in digits: + digit = int(s[index]) + num = num*10 + digit + index += 1 + + # apply signedness + + num = -num if is_negative else num + + # Process rounding + INT_MIN = -2**31 + INT_MAX = 2**31 -1 + num = min(num, INT_MAX) + num = max(num, INT_MIN) + return num +``` + +- `ord`や、文字列の比較を忘れていた +- leading zero の処理を別途書いたが、これはなくても良かった ## step4 (FB) diff --git a/8_string_to_integer_atoi_medium/step3.py b/8_string_to_integer_atoi_medium/step3.py index 24ab7a1..635c06f 100644 --- a/8_string_to_integer_atoi_medium/step3.py +++ b/8_string_to_integer_atoi_medium/step3.py @@ -7,7 +7,45 @@ # @lc code=start class Solution: def myAtoi(self, s: str) -> int: - return 0 + if not s: + return 0 + index = 0 + # Process whitespace + SPACE = " " + while index < len(s) and s[index] == SPACE: + index += 1 + + # Process signedness + is_negative = False + MINUS = "-" + PLUS = "+" + if index < len(s) and s[index] == MINUS: + is_negative = True + index += 1 + elif index < len(s) and s[index] == PLUS: + index += 1 + + # Process conversion + num = 0 + # leading zeros + while index < len(s) and s[index] == str(0): + index += 1 + digits = [str(i) for i in range(10)] + while index < len(s) and s[index] in digits: + digit = int(s[index]) + num = num*10 + digit + index += 1 + + # apply signedness + + num = -num if is_negative else num + + # Process rounding + INT_MIN = -2**31 + INT_MAX = 2**31 -1 + num = min(num, INT_MAX) + num = max(num, INT_MIN) + return num # @lc code=end From 87745ab039712939b1c322174ad94d9f6606aab7 Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 9 Nov 2025 17:28:03 +0900 Subject: [PATCH 5/6] Update README --- 8_string_to_integer_atoi_medium/README.md | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/8_string_to_integer_atoi_medium/README.md b/8_string_to_integer_atoi_medium/README.md index 6c81d7e..70ad96c 100644 --- a/8_string_to_integer_atoi_medium/README.md +++ b/8_string_to_integer_atoi_medium/README.md @@ -60,8 +60,8 @@ class Solution: - 次に前から空白を取り除く処理を実装したが、何度かバグを踏んだ - `while i < len(s) and ...`と先にandしておくと、`i`が`len(s)`に達したときに`s[i]`でIndexErrorになる問題を防げる -- 時間計算量:`O(n)` -- 空間計算量:`O(n)` +- 時間計算量:`O(len(s))` +- 空間計算量:`O(1)` Tests - standard cases: @@ -205,18 +205,6 @@ class Solution: ## step4 (FB) - -# 別解・模範解答 - -- 時間計算量:`O(n)` -- 空間計算量:`O(n)` - -# 想定されるフォローアップ質問 - -## CS 基礎 - -## システム設計 - ## その他 # 次に解く問題の予告 From 3ec72f994bcd5f5410c239df1b11264df1497f3a Mon Sep 17 00:00:00 2001 From: Kaichi-Irie Date: Sun, 9 Nov 2025 17:28:49 +0900 Subject: [PATCH 6/6] Update README --- 8_string_to_integer_atoi_medium/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/8_string_to_integer_atoi_medium/README.md b/8_string_to_integer_atoi_medium/README.md index 70ad96c..0fa21a8 100644 --- a/8_string_to_integer_atoi_medium/README.md +++ b/8_string_to_integer_atoi_medium/README.md @@ -208,4 +208,4 @@ class Solution: ## その他 # 次に解く問題の予告 -- Permutations +- [Number of Islands](https://leetcode.com/problems/number-of-islands/description/)