-
Notifications
You must be signed in to change notification settings - Fork 0
8. String to Integer (atoi) #60
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,202 @@ | ||
| # Step1 | ||
|
|
||
| ## 条件の確認 | ||
|
|
||
| * stringをintegerに変えるパーサーみたいなものを作る | ||
| * stringには数字, 符号, 空白以外も含まれるか? | ||
| * 上記と`.`, ` `, english lettersが含まれる | ||
| * leading white spaceが存在するか | ||
| * 存在するから無視する | ||
| * leading zeroが存在するか | ||
| * 存在する | ||
| * `.`が二つ以上存在するか(数字としてはinvalid) | ||
| * `+`や`-`が途中に存在するか | ||
| * non_digit characterが来たら読み取りを終了 | ||
| * 小数は考慮しなくていい | ||
| * 数字の途中に空白が入ることはあるか?入る場合はどう扱うか. 無視 or 終了 | ||
| * 文字列の長さはどのくらいか | ||
| * 32bit の範囲に収める必要がある | ||
|
|
||
| ## アプローチ | ||
|
|
||
| * state machine的に解きたい | ||
| * leading white spaceを読み取る | ||
| * 符号を読み取る | ||
| * leading zeroを読み取る | ||
| * 数字を読み取る | ||
| * 計算量: O(N) | ||
| * 実行時間: 200 / 10^6 ~= 2 * 10^-4 sec程度 | ||
|
|
||
| ## Code1-1 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def myAtoi(self, s: str) -> int: | ||
| if not s: | ||
| return 0 | ||
|
|
||
| i = 0 | ||
|
|
||
| # ignore leading spaces | ||
| while i < len(s) and s[i] == " ": | ||
| i += 1 | ||
|
|
||
| if i == len(s): | ||
| return 0 | ||
|
|
||
| # read sign | ||
| is_positive = True | ||
| if s[i] == "+": | ||
| i += 1 | ||
| elif s[i] == "-": | ||
| is_positive = False | ||
| i += 1 | ||
|
|
||
| # read digits | ||
| is_leading_zeroes = True | ||
| number = 0 | ||
| while i < len(s) and s[i].isdigit(): | ||
| # ignore leading zeroes | ||
| if is_leading_zeroes: | ||
| if s[i] == "0": | ||
| i += 1 | ||
| continue | ||
| else: | ||
| is_leading_zeroes = False | ||
| continue | ||
|
|
||
| number = number * 10 + int(s[i]) | ||
| i += 1 | ||
|
|
||
|
|
||
| if is_positive: | ||
| return min(number, 2**31 - 1) | ||
| else: | ||
| return -1 * min(number, 2**31) | ||
|
|
||
| ``` | ||
|
|
||
| # Step2 | ||
|
|
||
| ## Code2-1 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def myAtoi(self, s: str) -> int: | ||
| i = 0 | ||
|
|
||
| # ignore leading white spaces | ||
| while i < len(s) and s[i] == " ": | ||
| i += 1 | ||
|
|
||
| if i == len(s): | ||
| return 0 | ||
|
|
||
| # read sign | ||
| is_negative = False | ||
| if s[i] in ["+", "-"]: | ||
| if s[i] == "-": | ||
| is_negative = True | ||
| i += 1 | ||
|
|
||
|
|
||
| # read digits | ||
| parsing_leading_zeroes = True | ||
| number = 0 | ||
| while i < len(s) and s[i].isdigit(): | ||
| # ignore leading zeroes | ||
| if parsing_leading_zeroes: | ||
| if s[i] == "0": | ||
| i += 1 | ||
| else: | ||
| parsing_leading_zeroes = False | ||
| # after leading zeroes | ||
| else: | ||
| number = number * 10 + int(s[i]) | ||
| i += 1 | ||
|
|
||
| if is_negative: | ||
| return -1 * min(number, 2**31) | ||
| else: | ||
| return min(number, 2**31 - 1) | ||
|
|
||
| ``` | ||
|
|
||
| ## 他の人のコードを見る | ||
|
|
||
| * https://github.com/olsen-blue/Arai60/pull/60 | ||
| * INT_MAXを超えた時点で, `return`するようにしたい | ||
| * 無限に値が増え続けてしまう(余計なメモリを使用する) | ||
| * https://github.com/naoto-iwase/leetcode/pull/60 | ||
| * `is_digit`だと, 丸数字や上付き数字でもTrueになる | ||
| * `is_dicimal`が今回だと厳密に数字を表せる | ||
| * あるいは`ord`を使うか | ||
| * pythonだと問題ないが, overflowを考慮する場合は, 値を計算する前に条件を確認する必要がある | ||
| * 以下のものがわかりやすかった | ||
|
|
||
| ```python | ||
| def _is_overflow(self, sign: int, value: int, digit: int) -> bool: | ||
| if sign == 1: | ||
| if value > MAX_INT // 10: | ||
| return True | ||
| if value == MAX_INT // 10 and digit > MAX_INT % 10: | ||
| return True | ||
| else: | ||
| if value < (MIN_INT + 9) // 10: | ||
| return True | ||
| if value == (MIN_INT + 9) // 10 and digit > (10 - MIN_INT % 10) % 10: | ||
| return True | ||
| return False | ||
| ``` | ||
|
|
||
| * https://github.com/mamo3gr/arai60/pull/54 | ||
| * 以下のコメントが参照されていた | ||
| * > 他の(オーバーフローが)問題になるような言語だと、標準ライブラリーにそういう関数があることが多いというのも意識してもいいかもしれません まあ、要は自分で作らないべきものであるということです。 | ||
|
|
||
| # Step3 | ||
|
|
||
| ## Code3-1 | ||
|
|
||
| * 1st: 5:32 | ||
| * 2nd: 3:05 | ||
| * 3rd: 6:57 | ||
|
|
||
| ```python | ||
| class Solution: | ||
| def myAtoi(self, s: str) -> int: | ||
| i = 0 | ||
|
|
||
| while i < len(s) and s[i] == " ": | ||
| i += 1 | ||
| if i == len(s): | ||
| return 0 | ||
|
|
||
| sign = 1 | ||
| if s[i] == "+": | ||
| i += 1 | ||
| elif s[i] == "-": | ||
| sign = -1 | ||
| i += 1 | ||
|
|
||
| is_leading_zeroes = False | ||
| num = 0 | ||
| while i < len(s) and s[i].isdecimal(): | ||
| if is_leading_zeroes: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. これは動かないですね。きっと。。。。 |
||
| if s[i] == "0": | ||
| i += 1 | ||
| continue | ||
| is_leading_zeroes = False | ||
| continue | ||
|
|
||
| num = num * 10 + (ord(s[i]) - ord("0")) | ||
| if sign == 1 and num > 2**31 - 1: | ||
| return 2**31 - 1 | ||
| if sign == -1 and num > 2**31: | ||
| return -2**31 | ||
|
|
||
| i += 1 | ||
|
|
||
| return sign * num | ||
|
|
||
|
|
||
| ``` | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isdecimalは「Unicode の decimal digit 全般」を表すため今回はUnicodeポイントを直接比較する方が良いと思います。'0' <= c <= '9'https://docs.python.org/3/library/stdtypes.html#str.isdecimal
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
知らなかったです。ありがとうございます