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
39 changes: 39 additions & 0 deletions grind75_hard/06_224_Basic Calculator/level_1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 数字符号も含め10進数に直して、最後に全部足し算する
# ()で囲まれた部分を先に計算するため、stackに入れておく
# 各文字に対する処理をそれぞれ記載
class Solution:
def calculate(self, s: str) -> int:
stack = []
sign = 1
num = 0
for c in s:
if c.isspace():
continue
if c.isdigit():
num = num * 10 + int(c)
continue
if c == "(":
stack.append((c, sign))
sign = 1
continue
if c == "-":
stack.append((num, sign))
sign = -1
if c == "+":
stack.append((num, sign))
sign = 1
if c == ")":
num *= sign
while 1:
expression, sign = stack.pop()
if expression == "(":
break
num += expression * sign
stack.append((num, sign))
num = 0
if num != 0:
stack.append((num, sign))
result = 0
for num, sign in stack:
result += num * sign
return result
29 changes: 29 additions & 0 deletions grind75_hard/06_224_Basic Calculator/level_2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# 括弧内の計算を再帰的に行う
class Solution:
def calculate(self, s: str) -> int:
def helper_calculate(index):
result = 0
num = 0
sign = 1
while index < len(s):
if s[index].isdigit():
num = num * 10 + int(s[index])
if s[index] == "+":
result += num * sign
num = 0
sign = 1
if s[index] == "-":
result += num * sign
num = 0
sign = -1
if s[index] == ")":
result += num * sign
return index, result
if s[index] == "(":
index, result_in_brackers = helper_calculate(index + 1)
result += result_in_brackers * sign
index += 1
result += num * sign
return result

return helper_calculate(0)
28 changes: 28 additions & 0 deletions grind75_hard/06_224_Basic Calculator/level_3.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
class Solution:
def calculate(self, s: str) -> int:
def helper_calculate(index):
num = 0
sign = 1
result = 0
while index < len(s):
if s[index].isdigit():
num = 10 * num + int(s[index])
Comment on lines +7 to +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.

"1 2" のような入力が12と出力されないですか?問題上そのような入力は来ないと思いますが。

Copy link
Copy Markdown
Owner Author

@shining-ai shining-ai May 14, 2024

Choose a reason for hiding this comment

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

この問題は電卓をイメージしていたので、"1 2"は12の認識でした。
ちょっと問題読み直してみます。

if s[index] == "+":
result += num * sign
num = 0
sign = 1
if s[index] == "-":
result += num * sign
num = 0
sign = -1
if s[index] == ")":
result += num * sign
return result, index
if s[index] == "(":
result_in_brackets, index = helper_calculate(index + 1)
result += result_in_brackets * sign
index += 1
result += num * sign
return result

return helper_calculate(0)
38 changes: 38 additions & 0 deletions grind75_hard/06_224_Basic Calculator/level_4.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# 再帰下降構文解析
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

単項演算子に対応できているでしょうか?
-1
という入力に対して何を返しますか?

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.

-1が返ります。
一応想定通りの挙動です。

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ソースコード読み直してみました。 -1 を expr() で処理する際、 factor() から 0 が返り、そのあと - が処理されて、 1 を引いているように見えます。実質 0 - 1 の処理を行っているようです。他の方がソースコードを読んだとき、見落とす可能性が高いと思います。単項演算子を明示的にケアしたほうが良いと思います。

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.

コメントの意図通りかわからないのですが、「-」始まりの計算単行演算子のケアしてみました。

if index < len(s) and s[index] == "-":
    index += 1
    result = -factor()
else:
    result = factor()

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

ありがとうございます。よいと思います。

class Solution:
def calculate(self, s: str) -> int:
index = 0

def get_next_expression():
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

get で始まる関数名は、何かを取得しているように見えます。 skip_spaces() はいかがでしょうか?

nonlocal index
index += 1
while index < len(s) and s[index].isspace():
index += 1

def expr():
nonlocal index
result = factor()
while index < len(s) and s[index] in "+-":
op = s[index]
get_next_expression()
if op == "+":
result += factor()
else:
result -= factor()
return result

def factor():
nonlocal index
result = 0
while index < len(s) and s[index].isdigit():
result = 10 * result + int(s[index])
get_next_expression()
if index < len(s) and s[index] == "(":
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

これは最初に持ってきて、 early return した方がシンプルになると思います。

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.

s[index].isdigit()
")"の後に数字は来ないから、無駄に条件判定させない方がいいということですね。

get_next_expression()
result = expr()
get_next_expression() # ")"を読み飛ばす
return result

if index < len(s) and s[0].isspace():
get_next_expression()
return expr()
39 changes: 39 additions & 0 deletions grind75_hard/06_224_Basic Calculator/level_5.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 再帰下降構文解析
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

入力文字列内のスペースを最初にすべて取り除いてしまっても良いように思いました。

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.

定数倍遅くなるのが気になり読み取りながら削除してましたが、最初に取り除いた方がシンプルですね。

class Solution:
def calculate(self, s: str) -> int:
index = 0

def skip_spaces():
nonlocal index
index += 1
while index < len(s) and s[index].isspace():
index += 1

def expr():
nonlocal index
result = factor()
while index < len(s) and s[index] in "+-":
op = s[index]
skip_spaces()
if op == "+":
result += factor()
else:
result -= factor()
return result

def factor():
nonlocal index
result = 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.

result に 0 を代入してから、 if 文の中で再度 expr() を代入している点に違和感を感じました。 result = 0 は、if 文が終わったあと、 while 文の前に持ってきた方が、読み手にとって分かりやすいと思います。

if index < len(s) and s[index] == "(":
skip_spaces()
result = expr()
skip_spaces() # ")"を読み飛ばす
return result
while index < len(s) and s[index].isdigit():
result = 10 * result + int(s[index])
skip_spaces()
return result

if index < len(s) and s[0].isspace():
skip_spaces()
return expr()
40 changes: 40 additions & 0 deletions grind75_hard/06_224_Basic Calculator/level_6.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# 再帰下降構文解析
# スペースを最初に除去
# result = 0のタイミングを修正
# 単行演算子を明示的に処理
class Solution:
def calculate(self, s: str) -> int:
index = 0

def expr():
nonlocal index
if index < len(s) and s[index] == "-":
index += 1
result = -factor()
else:
result = factor()

while index < len(s) and s[index] in "+-":
op = s[index]
index += 1
if op == "+":
result += factor()
else:
result -= factor()
return result

def factor():
nonlocal index
if index < len(s) and s[index] == "(":
index += 1
result = expr()
index += 1 # ")"を読み飛ばす
return result
result = 0
while index < len(s) and s[index].isdigit():
result = 10 * result + int(s[index])
index += 1
return result

s = s.replace(" ", "")
return expr()