Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions arai60/atoi/phase1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
INT_MAX = 2 ** 31 -1
INT_MIN = - 2 ** 31
# 仮に数字の場合文字列の最初に来うるのは符号か数字のみ
# 符号が来た場合も次の文字が数字じゃなければならない
# is_number -> extract_number(integer部分を抜き取る) -> 数字化処理

def char_is_number(char: str)->bool:
if ord(char) >= ord("0") and ord("9") >= ord(char):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

直後に return True/False を行っています。この場合、 if 文の条件式をそのまま返したほうがシンプルになると思います。

また、不等号の向きは

  • 比較される側を常に左に置く
  • 数直線上に一直線に並ぶよう、左から右に、小さいほうから大きいほうに並べる

等の流派があります。複数の書き方で書けるようにして置き、チーム内でよく書かれる書き方で書けるようにしておくとよいと思います。

今回の場合は、 return ord("0") <= ord(char) and ord(char) <= ord("9") あたりが良いと思います。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pythonならreturn ord("0") <= ord(char) <= ord("9")もできますね。
この問題だと、isdigitを使ってもいいです。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

一応, ここでの会話(cheeseNA/leetcode#5 (comment)) を見てisdigitは使わない方向にしてみました。

return True
return False

def is_number(s: str)->bool:
for index, char in enumerate(s):
if char == " ":
continue
elif char == "-" or char == "+":
if index == len(s) - 1:
#符号が終端の場合
return False
else:
#次の文字が数字かどうかで判断
return char_is_number(s[index+1])
elif char_is_number(char):
return True
else:
return False
return False

def search_start_index(s: str)->int:
for index, char in enumerate(s):
if char == "+" or char == "-":
return index
elif char_is_number(char):
return index

def extract_number(s: str)->str:
start_index = search_start_index(s)
end_index = len(s)
for index in range(start_index+1, len(s)):
if not char_is_number(s[index]):
end_index = index
break
return s[start_index:end_index]

def string_to_integer(s: str)->int:
if not is_number(s):
return 0

extracted_number_string = extract_number(s)
sign = 1
if extracted_number_string[0] == "-":
sign = -1
extracted_number_string = extracted_number_string[1:]
elif extracted_number_string[0] == "+":
extracted_number_string = extracted_number_string[1:]

after_atoi_number = 0
for index, char in enumerate(extracted_number_string):
digit = len(extracted_number_string) - index - 1
after_atoi_number += (ord(char)-ord("0")) * 10 ** digit

return after_atoi_number * sign



def clamp(number: int) -> int:
if number > INT_MAX:
return INT_MAX
elif number < INT_MIN:
return INT_MIN
return number
54 changes: 54 additions & 0 deletions arai60/atoi/phase2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# https://github.com/cheeseNA/leetcode/pull/5/files
# まず空白に関してカーソルを動かす, そのあと符号に関してカーソルを動かし, 数字が続く限りwhileで処理をしていた。
# 僕のphase1の解答と違いif文に関しての複雑な制御がいらなくて賢かった。(でもatoiを作れという課題なのにpythonのintを使ってるのはどうなんだろう)

# https://github.com/usatie/leetcode/commit/9b4ea58330b31c3c1371fe242bc02ab1a9012329
# 上のほぼC++版, 上もだがオーバーフローは最後に確認ではなく逐次確認の方が良いのだと思った
# 最後に確認する方法だと下手したらオーバーフローが二周してくる場合とかもあるなと思った

INT_MAX = 2 ** 31 -1
INT_MIN = - 2 ** 31

def char_is_number(char: str)->bool:
if ord(char) >= ord("0") and ord("9") >= ord(char):
return True
return False

def string_to_integer(s: str)->int:
if len(s) == 0:
return 0

current_pointer = 0
while current_pointer < len(s):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whlie while current_pointer < len(s) and s[current_pointer] == " ": で良いと思います。

# 空白に関して処理をする
if s[current_pointer] != " ":
break
current_pointer += 1
if current_pointer == len(s):
return 0

sign = 1
#符号処理
if s[current_pointer] == "+":
current_pointer += 1
elif s[current_pointer] == "-":
sign = -1
current_pointer += 1

abs_value = 0
while current_pointer < len(s) and char_is_number(s[current_pointer]):
abs_value *= 10
abs_value += ord(s[current_pointer]) - ord("0")
if abs_value * sign > INT_MAX:
return INT_MAX
elif abs_value * sign < INT_MIN:
return INT_MIN
current_pointer += 1

return abs_value * sign


class Solution:
def myAtoi(self, s: str) -> int:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

myAtoi() は実質 string_to_integer() のラッパーになっているように思います。あえてラップする意味はないと思います。 string_to_integer() の中身をここに書いてしまったほうが良いと思います。

after_atoi_number = string_to_integer(s)
return after_atoi_number
44 changes: 44 additions & 0 deletions arai60/atoi/phase3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
INT_MAX = 2 ** 31 - 1
INT_MIN = - 2 ** 31
def char_is_number(char: str)->int:
if ord(char) >= ord("0") and ord("9") >= ord(char):
return True
return False

def string_to_integer(s: str)->int:
if len(s) == 0:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

このチェックは不要そうです。

return 0

current_pointer = 0
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

indexまたはiでどうでしょう。

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while current_pointer < len(s):
if s[current_pointer] != " ":
break
current_pointer += 1

if current_pointer == len(s):
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while-else が一応ありますか?

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

while-else文知らなかったです...

return 0

sign = 1
# 符号処理
if s[current_pointer] == "+":
current_pointer += 1
elif s[current_pointer] == "-":
sign = -1
current_pointer += 1

abs_value = 0
while current_pointer < len(s) and char_is_number(s[current_pointer]):
abs_value *= 10
abs_value += ord(s[current_pointer]) - ord("0")
if abs_value * sign > INT_MAX:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

もし32-bitのintしか使えない状況だったら、どうやって判定するかも考えてみてもいいかもしれません。

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

計算前のabs_valueの値を取っておいて, 計算後に符号が変わっていたらオーバーフローしているので, signに従ってINT_MAXかINT_MINを出力という感じでしょうか

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

signed intのオーバフーローは、C++ではundefined behaviorみたいです。unsigned intを使えば簡単に確認できますが、もしintしか使えないという制約のもとでは、10倍して次の数字を足す前に確認できそうです。
https://stackoverflow.com/questions/16188263/is-signed-integer-overflow-still-undefined-behavior-in-c

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ちょうど今C++でも書いていたんですが, runの時点panicを引き起こしました

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rustなどだとオーバーフロー制御があるので書きやすいので, そちらでも時間があったら書いてみます

return INT_MAX
elif abs_value * sign < INT_MIN:
return INT_MIN
current_pointer += 1

return abs_value * sign

class Solution:
def myAtoi(self, s: str) -> int:
after_atoi_number = string_to_integer(s)
return after_atoi_number
34 changes: 34 additions & 0 deletions arai60/atoi/phase4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
INT_MAX = 2 ** 31 - 1
INT_MIN = - 2 ** 31

def char_is_number(c: str)->bool:
return ord("0") <= ord(c) <= ord("9")

class Solution:
def myAtoi(self, s: str) -> int:
index = 0
while index < len(s) and s[index] == " ":
index += 1

if index == len(s):
return 0

sign = 1
if s[index] == "+":
index += 1
elif s[index] == "-":
sign = -1
index += 1

absolute_value = 0
while index < len(s) and char_is_number(s[index]):
absolute_value *= 10
absolute_value += ord(s[index]) - ord("0")
if absolute_value * sign > INT_MAX:
return INT_MAX
elif absolute_value * sign < INT_MIN:
return INT_MIN
index += 1

return absolute_value * sign