From 86409ac96581d258d8625fa613a41157e7dd9f3e Mon Sep 17 00:00:00 2001 From: yamashita-ki Date: Mon, 15 Sep 2025 15:48:30 +0900 Subject: [PATCH] =?UTF-8?q?step3=E3=81=BE=E3=81=A7=E5=AE=9F=E6=96=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 150. Evaluate Reverse Polish Notation.md | 158 +++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 150. Evaluate Reverse Polish Notation.md diff --git a/150. Evaluate Reverse Polish Notation.md b/150. Evaluate Reverse Polish Notation.md new file mode 100644 index 0000000..86e4dd1 --- /dev/null +++ b/150. Evaluate Reverse Polish Notation.md @@ -0,0 +1,158 @@ +## step1 とりあえず解く +- 計算量 + - 時間:O(N) + - 空間:O(N) +- 素直にArrayDequeをStackとして使用して求めた +- 見直すと `calculateFromOperator` というメソッド名は若干冗長に感じる + - 計算に演算子と非演算子を渡すことは自然であるため `calculate` でよかったかも +- `calculateFromOperator` の分岐はswitch式のが簡潔にかけたと思う + +```java +class Solution { + + public int evalRPN(String[] tokens) { + ArrayDeque numStack = new ArrayDeque<>(); + Set operators = new HashSet<>(Arrays.asList("*", "-", "+", "/")); + for (String token : tokens) { + if (operators.contains(token)) { + int rightNum = numStack.pollLast(); + int leftNum = numStack.pollLast(); + numStack.add(this.calculateFromOperator(leftNum, rightNum, token)); + } else { + numStack.add(Integer.parseInt(token)); + } + } + return numStack.peekLast(); + } + + private int calculateFromOperator(int leftNum, int rightNum, String operator) { + if (operator.equals("+")) { + return leftNum + rightNum; + } + if (operator.equals("-")) { + return leftNum - rightNum; + } + if (operator.equals("*")) { + return leftNum * rightNum; + } + if (operator.equals("/")) { + return leftNum / rightNum; + } + throw new RuntimeException(); + } +} + +``` + +## step2 他の人の回答を見る +- 計算量 + - 時間:O(N) + - 空間:O(N) +- やはりStackを使った回答が多かった +- 計算するメソッドは別で切り出したほうが、重複の削除や責任の分離という面でも良さそう + +```java +class Solution { + public int evalRPN(String[] tokens) { + Stack stack = new Stack<>(); + for (String c : tokens) { + if (c.equals("+")) { + stack.push(stack.pop() + stack.pop()); + } else if (c.equals("-")) { + int a = stack.pop(); + int b = stack.pop(); + stack.push(b - a); + } else if (c.equals("*")) { + stack.push(stack.pop() * stack.pop()); + } else if (c.equals("/")) { + int a = stack.pop(); + int b = stack.pop(); + stack.push(b / a); + } else { + stack.push(Integer.parseInt(c)); + } + } + return stack.pop(); + } +} +``` + +- 再帰的に解く方法もあった +- 計算量 + - 時間:O(N) + - 空間:O(N) + +```java +public class Solution { + public int evalRPN(String[] tokens) { + List tokenList = new ArrayList<>(Arrays.asList(tokens)); + return dfs(tokenList); + } + + private int dfs(List tokens) { + String token = tokens.remove(tokens.size() - 1); + + if (!"+-*/".contains(token)) { + return Integer.parseInt(token); + } + + int right = dfs(tokens); + int left = dfs(tokens); + + switch (token) { + case "+": + return left + right; + case "-": + return left - right; + case "*": + return left * right; + case "/": + return left / right; + } + + return 0; + } +} +``` + +## step3 3回とく +- 異常系の処理と、stackから値を取り出す前のチェックを追加 + +```java +class Solution { + public int evalRPN(String[] tokens) { + if(tokens.length == 0) { + return 0; + } + + ArrayDeque stack = new ArrayDeque<>(); + Set operators = new HashSet<>(Arrays.asList("-", "+", "*", "/")); + + for(String token : tokens) { + if(operators.contains(token) && stack.size() >= 2) { + int rightNum = stack.pollLast(); + int leftNum = stack.pollLast(); + stack.add(this.calculate(leftNum, rightNum, token)); + } else { + stack.add(Integer.parseInt(token)); + } + } + return stack.peekLast(); + } + + private int calculate(int leftNum, int rightNum, String operator) { + switch(operator) { + case "+": + return leftNum + rightNum; + case "-": + return leftNum - rightNum; + case "*": + return leftNum * rightNum; + case "/": + return leftNum / rightNum; + } + throw new RuntimeException(); + } +} + +``` \ No newline at end of file