diff --git a/stack/20_valid_parentheses/20.md b/stack/20_valid_parentheses/20.md new file mode 100644 index 0000000..622e925 --- /dev/null +++ b/stack/20_valid_parentheses/20.md @@ -0,0 +1,111 @@ +# 1st +- 前提: Arai60は一度一周しているが、期間をあけてなるべく忘れて取り組む(linkedList の方で思い出しながらと書きましたが、なるべく初見の状態で、どれだけやれるようになったかみていきたい) +- 問題: [20. Valid Parentheses](https://leetcode.com/problems/valid-parentheses/description/) +- コメント集: [20. Valid Parentheses](https://docs.google.com/document/d/11HV35ADPo9QxJOpJQ24FcZvtvioli770WWdZZDaLOfg/edit?tab=t.0#heading=h.ns0bie22a6m) + - 引数に想定外がきた時はどうする?が気になったので実装に含めてみました + - 引数に対して、想定しない値がの場合は `IllegalArgumentException` を投げるようにしました + - が、コンパイルとか Linter のことを考えると、`(ai){ueo}` みたいなのが来たときは continue とかの方が良いのかもと思ったりしたので別解として載せました +- 所感 + - コンパイル、 Linter で高速に動いてくれないと困るよなと思いました + +### 実装 +- 時間計算量: O(N) --> 引数 s を全て走査するから +- 空間計算量: O(N) --> open の記号だけ Stack につめる、最悪全て open 記号だから +- 回答時間: 無制限(コメントをちゃんと読んでみたり、変数名の命名にこだわったりしてみました) + +```java +class Solution { + private static final Map validParentheses = Map.of( + '(', ')', + '[', ']', + '{', '}' + ); + + public boolean isValid(String s) { + Deque openSymbols = new ArrayDeque<>(); + for (int i = 0; i < s.length(); i++) { + char symbol = s.charAt(i); + + if (isIllegalSymbol(symbol)) { + throw new IllegalArgumentException("Invalid Character is detected, symbol is " + symbol); + } + + if (isOpenSymbol(symbol)) { + openSymbols.push(symbol); + } else { + if (openSymbols.empty()) { + return false; + } + char peekedOpenSymbol = openSymbols.peek(); + if (isMatched(symbol, peekedOpenSymbol)) { + openSymbols.pop(); + } else { + // 合致しない時点で false + return false; + } + } + } + return openSymbols.empty(); + } + + private boolean isIllegalSymbol(char symbol) { + return !validParentheses.containsKey(symbol) && !validParentheses.containsValue(symbol); + } + + private boolean isOpenSymbol(char symbol) { + return validParentheses.containsKey(symbol); + } + + private boolean isMatched(char symbol, char peekedOpenSymbol) { + return validParentheses.get(peekedOpenSymbol) == symbol; + } +} +``` + +- 別解 + - `isIllegalSymbol()` を削除し、引数として妥当でない場合は `continue` する方針にしました + - コンパイラとか Linter でこんな処理が動いているんだろうなで書きました +```java +class Solution { + private static final Map validParentheses = Map.of( + '(', ')', + '[', ']', + '{', '}' + ); + + public boolean isValid(String s) { + Deque openSymbols = new ArrayDeque<>(); + for (int i = 0; i < s.length(); i++) { + char symbol = s.charAt(i); + + if (isOpenSymbol(symbol)) { + openSymbols.push(symbol); + } else if (isCloseSymbol(symbol)) { + if (openSymbols.empty()) { + return false; + } + char peekedOpenSymbol = openSymbols.peek(); + if (isMatched(symbol, peekedOpenSymbol)) { + openSymbols.pop(); + } else { + // 合致しない時点で false + return false; + } + } + } + return openSymbols.empty(); + } + + private boolean isOpenSymbol(char symbol) { + return validParentheses.containsKey(symbol); + } + + private boolean isCloseSymbol(char symbol) { + return validParentheses.containsValue(symbol); + } + + private boolean isMatched(char symbol, char peekedOpenSymbol) { + return validParentheses.get(peekedOpenSymbol) == symbol; + } +} +```