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 0227.Basic-Calculator-II/memo.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# 227. Basic Calculator II

## step1
とりあえず答えを合わせるために書き上げたもの: step1。これでも文法ミスなどで25mほどかかった。

確認: // -> 常に小さい方向に丸める, int(・ / ・) -> 小数点以下を切り捨て

## 他の人のコード

https://leetcode.com/problems/basic-calculator-ii/solutions/7632696/a-simple-solution-by-santhanapandis-5vtt/

最後に番兵として "+" を足す

https://github.com/potrue/leetcode/pull/64

## step2

無駄が多いので書き直す。一巡目で+-も処理できる。

さらに例外処理を追加。

再帰下構文解析で書く。

空ではかけず以下の自分の解法を見ながら書いた。

https://leetcode.com/problems/basic-calculator/description/


以下の文法に従う

```
expr := term [ ('+' or '-') term ]*
term := factor [ ('*' or '/') factor ]*
factor := digit+
```

## step3

再帰下構文解析を練習する
60 changes: 60 additions & 0 deletions 0227.Basic-Calculator-II/step1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
class Solution:
def calculate(self, s: str) -> int:
def parse_number(left):
number = 0
right = left
while right < len(s) and s[right].isdigit():
right += 1

return s[left:right], right

operator_to_func = {
"*": lambda ops: ops[0] * ops[1],
"/": lambda ops: ops[0] // ops[1],
}

to_be_calculated = []
i = 0
result = 0
sign = 1
while i < len(s):
if s[i] == " ":
i += 1
elif s[i].isdigit():
number, i = parse_number(i)
to_be_calculated.append(number)
elif s[i] in ["*", "/"]:
operator = s[i]
op1 = to_be_calculated.pop()
i += 1
while s[i] == " ":
i += 1
assert s[i].isdigit(), s[i]
op2, i = parse_number(i)
number = operator_to_func[operator]((int(op1), int(op2)))
to_be_calculated.append(str(number))
elif s[i] in ["+", "-"]:
to_be_calculated.append(s[i])
i += 1
else:
raise RuntimeError("invalid input")

result = 0
sign = 1
number = 0
i = 0
print(to_be_calculated)
while i < len(to_be_calculated):
if to_be_calculated[i].isdigit():
result += int(to_be_calculated[i]) * sign
i += 1
elif to_be_calculated[i] == "+":
sign = 1
i += 1
elif to_be_calculated[i] == "-":
sign = -1
i += 1
else:
raise RuntimeError("invalid input")

return result
26 changes: 26 additions & 0 deletions 0227.Basic-Calculator-II/step2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class Solution:
def calculate(self, s: str) -> int:
stack = []
number = 0
op = "+"

i = 0
while i < len(s):
if s[i].isdigit():
number = number * 10 + int(s[i])

if s[i] in ["+", "-", "*", "/"] or i == len(s):
if op == "+":
stack.append(number)
elif op == "-":
stack.append(-number)
elif op == "*":
stack.append(stack.pop() * number)
elif op == "/":
stack.append(int(stack.pop() / number))
op = s[i]
number = 0

i += 1

return sum(stack)
36 changes: 36 additions & 0 deletions 0227.Basic-Calculator-II/step2_error_handling.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Solution:
def calculate(self, s: str) -> int:
stack = []
number = 0
op = "+"

i = 0
expect_number = True

while i < len(s):
if i != len(s) - 1 and s[i] == " ":
i += 1
continue
elif s[i].isdigit():
number = number * 10 + int(s[i])
expect_number = False
elif expect_number or s[i] not in ["+", "-", "*", "/", " "]:
raise ValueError(f"invalid input: {s[i]}")

if s[i] in ["+", "-", "*", "/"] or i == len(s) - 1:
if op == "+":
stack.append(number)
elif op == "-":
stack.append(-number)
elif op == "*":
stack.append(stack.pop() * number)
elif op == "/":
if number == 0:
raise ZeroDivisionError("Division by zero")
stack.append(int(stack.pop() / number))
op = s[i]
number = 0
expect_number = True
i += 1

return sum(stack)
47 changes: 47 additions & 0 deletions 0227.Basic-Calculator-II/step2_parsing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
expr := term [ ('+' or '-') term ]*
term := factor [ ('*' or '/') factor ]*
factor := digit+
"""


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

def expr():
nonlocal index
result = term()
while index < len(s) and s[index] in ["+", "-"]:
op = s[index]
index += 1
if op == "+":
result += term()
else:
result -= term()

return result

def term():
nonlocal index
result = factor()
while index < len(s) and s[index] in ["*", "/"]:
op = s[index]
index += 1
if op == "*":
result *= factor()
else:
result = int(result / factor())

return result

def factor():
nonlocal index
result = 0
while index < len(s) and s[index].isdigit():
result = result * 10 + int(s[index])
index += 1
return result

return expr()
47 changes: 47 additions & 0 deletions 0227.Basic-Calculator-II/step3_parsing.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
expr := term [ ('+' or '-') term ]*
term := factor [ ('*' or '/') factor ]*
factor := digit+
"""


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

def expr():
nonlocal index
result = term()
while index < len(s) and s[index] in ("+", "-"):
op = s[index]
index += 1
if op == "+":
result += term()
else:
result -= term()

return result

def term():
nonlocal index
result = factor()
while index < len(s) and s[index] in ("*", "/"):
op = s[index]
index += 1
if op == "*":
result *= factor()
else:
result = int(result / factor())

return result

def factor():
nonlocal index
result = 0
while index < len(s) and s[index].isdigit():
result = result * 10 + int(s[index])
index += 1
return result

return expr()