-
Notifications
You must be signed in to change notification settings - Fork 0
150. Evaluate Reverse Polish Notation #9
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 |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| ## step1 とりあえず解く | ||
| - 計算量 | ||
| - 時間:O(N) | ||
| - 空間:O(N) | ||
| - 素直にArrayDequeをStackとして使用して求めた | ||
| - 見直すと `calculateFromOperator` というメソッド名は若干冗長に感じる | ||
| - 計算に演算子と非演算子を渡すことは自然であるため `calculate` でよかったかも | ||
| - `calculateFromOperator` の分岐はswitch式のが簡潔にかけたと思う | ||
|
|
||
| ```java | ||
| class Solution { | ||
|
|
||
| public int evalRPN(String[] tokens) { | ||
| ArrayDeque<Integer> numStack = new ArrayDeque<>(); | ||
| Set<String> 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)); | ||
|
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. メソッド呼び出しの this. は省略してよいと思います。 |
||
| } 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<Integer> stack = new Stack<>(); | ||
|
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. ArrayDeque のほうが高速なため、 ArrayDeque を優先的に使用したほうが良いと思います。 https://docs.oracle.com/javase/jp/8/docs/api/java/util/ArrayDeque.html
|
||
| for (String c : tokens) { | ||
| if (c.equals("+")) { | ||
| stack.push(stack.pop() + stack.pop()); | ||
|
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. 個人的には step1 のように 4 種類の演算を同じようなロジックで書いたほうが、読み手にとってパターンマッチングで読めるので読みやすく、かつ書き間違えにくいと思います。 |
||
| } 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<String> tokenList = new ArrayList<>(Arrays.asList(tokens)); | ||
| return dfs(tokenList); | ||
| } | ||
|
|
||
| private int dfs(List<String> tokens) { | ||
|
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. 関数名には、内部の実装の詳細を表す言葉より、入力に対してどのような処理を行うのか、どのような値を返すかが分かるものを付けたほうが、読み手にとって分かりやすいと思います。 |
||
| 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<Integer> stack = new ArrayDeque<>(); | ||
| Set<String> operators = new HashSet<>(Arrays.asList("-", "+", "*", "/")); | ||
|
|
||
| for(String token : tokens) { | ||
|
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. for 文の後にスペースを空けることをおすすめします。 参考までにスタイルガイドへのリンクを貼ります。 https://google.github.io/styleguide/javaguide.html#s4.6.2-horizontal-whitespace
上記のスタイルガイドは唯一絶対のルールではなく、複数あるスタイルガイドの一つに過ぎないということを念頭に置くことをお勧めします。また、所属するチームにより何が良いとされているかは変わります。自分の中で良い書き方の基準を持ちつつ、チームの平均的な書き方で書くことをお勧めいたします。 |
||
| 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(); | ||
| } | ||
| } | ||
|
|
||
| ``` | ||
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.
Set.of() のほうがシンプルに書けると思います。
https://docs.oracle.com/javase/jp/11/docs/api/java.base/java/util/Set.html
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.
ご確認ありがとうございます!
勉強になりますmm