20. 有効な括弧
質問の意味:
'('
、')'
、'{'
、'}'
、のみを含む 文字列 を指定すると'['
、 その文字列が有効かどうかを判断します。']'
s
有効な文字列は次の条件を満たす必要があります。
- 開始ブラケットは、同じタイプの終了ブラケットで閉じる必要があります。
- 開き括弧は正しい順序で閉じる必要があります。
- すべての右ブラケットには、同じタイプの対応する左ブラケットがあります。
【入力例】 s="({})"
[出力サンプル] true
問題解決のアイデア:
古典的なスタックのアイデアは、配列を使用してスタックをシミュレートし、文字列を最初からたどって、左括弧をスタックにプッシュし、右括弧が見つかったらスタックの先頭をポップアップし、一致するかどうかを確認することです。一致しない場合は false を返します。
class Solution {
public boolean isValid(String s) {
if(s.length() %2 ==1){
//长度为奇数,肯定不匹配
return false;
}
Map<Character,Character> map = new HashMap<Character,Character>();
map.put(')','(');
map.put('}','{');
map.put(']','[');
List<Character> stack = new ArrayList<>();
for(int i=0;i<s.length();++i){
if(!map.containsKey(s.charAt(i))){
//左括号入栈
stack.add(s.charAt(i));
}else{
//右括号要出栈匹配
//栈为空或者栈顶元素与当前右括号不匹配
if(stack.isEmpty() || map.get(s.charAt(i)) != stack.get(stack.size()-1)){
return false;
}
//匹配上,要弹出栈顶元素
stack.remove(stack.size()-1);
}
}
return stack.isEmpty();
}
}
タイム: 50.23% を達成
メモリ: 28.36% の差
71. パスを単純化する
質問の意味:
ファイルまたはディレクトリを指す
path
Unix スタイルの 絶対パス ( で始まる) を表す文字列が与えられています 。これをより簡潔な正規パスに変換してください。'/'
Unix スタイルのファイル システムでは、ドット (
.
) は現在のディレクトリ自体を表し、さらに 2 つのドット (..
) は前のレベル (親ディレクトリを指す) へのディレクトリの変更を表します。両方とも複雑な相対パスの一部である可能性があります。 。任意の数の連続したスラッシュ (つまり、'//'
) は 1 つのスラッシュとして扱われます'/'
。この質問では、他の形式のドット (たとえば、'...'
) はファイル/ディレクトリ名として扱われます。返される正規パスは 次の形式に従う必要があることに注意してください 。
- 常にスラッシュで始まります
'/'
。- 2 つのディレクトリ名の間には、スラッシュが 1 つだけ必要です
'/'
。- 最後のディレクトリ名 (存在する場合) をで 終わらせることはできません
'/'
。- さらに、 path には、ルート ディレクトリからターゲット ファイルまたはディレクトリまでのパス上のディレクトリのみが含まれます (つまり、
'.'
または は 付きません'..'
)。簡略化された正規パスを返します 。
【入力例】 path="/home/"
【出力例】「/home」
問題解決のアイデア:
1. 指定された文字列を「/」に従って分割します。分割後は、空の文字列、1 つのドット (.)、2 つのドット (..) の 3 つの状況があります。
2. 分割された文字列をスキャンし、ディレクトリ名をスタックに保存します。
空の文字列が複数または 1 つに出現するため、空の文字列が見つかった場合はスキップします。
3. 「.」が見つかった場合、それは処理されず、現在のディレクトリ自体を示します。
4. 「..」が出現すると、スタックの最上位ディレクトリがポップアップし、前のレベルに切り替わります。
class Solution {
public String simplifyPath(String path) {
String[] splitPath = path.split("/");
List<String> stack = new ArrayList<>();
for(String current:splitPath){
if("..".equals(current)){
//出栈,切换到上一级目录,要不为空
if(!stack.isEmpty()){
stack.remove(stack.size()-1);
}
}else if(current.length() > 0 && !".".equals(current)){
//当前的字符串长度大于0,表示不是空字符串,当前的字符也不是·,进栈
stack.add(current);
}
}
//拼接,空的时候也要返回一个/
StringBuffer result = new StringBuffer();
if(stack.isEmpty()){
result.append("/");
}else{
//不为空,一直读出,直到空
int n = 0;
while(n<stack.size()){
result.append("/");
result.append(stack.get(n));
++n;
}
}
return result.toString();
}
}
タイム: 94.43% を達成
メモリ: 77.54% 上回る
155. 最小スタック
質問の意味:
push
、 、pop
演算をサポートしtop
、一定時間で最小の要素を取得できるスタックを設計します 。実装
MinStack
クラス:
MinStack()
スタックオブジェクトを初期化します。void push(int val)
要素 val をスタックにプッシュします。void pop()
スタックの最上位にある要素を削除します。int top()
スタックの最上位にある要素を取得します。int getMin()
スタック内の最小の要素を取得します。
【入力サンプル】
["MinStack","push","push","push","getMin","pop","top","getMin"] [[],[-2],[0],[-3 ] 、[]、[]、[]、[]]【出力サンプル】
[ヌル、ヌル、ヌル、ヌル、-3、ヌル、0、-2]
問題解決のアイデア:
一見、この質問は難しくないようですが、実際に最も重要なことは、最小値を取得する関数の実装です。
最初に入手したときは、グローバル変数 min を定義して、プッシュするたびに比較して、最小の値を格納できるようにしようと考えました。ただし、スタックをポップするときに、保存されている最小値がポップされる可能性があることは無視されます。
正しいアプローチは、k 個のデータが残っているときに追加のスタックを開き、スタックの最小値を格納することです。
1.minStack先存Integer.MAX_VALUE;
2. stack がプッシュ操作を実行すると、minStack にはそのときの最小値 Math.min(minStack.peek(), val); も格納されます。
3. スタックがポップ操作を実行する場合、一貫性を実現するために minStack もポップ操作を実行する必要があります。
class MinStack {
Deque<Integer> stack;
Deque<Integer> minStack;
public MinStack() {
stack = new LinkedList<Integer>();
minStack = new LinkedList<Integer>();
minStack.push(Integer.MAX_VALUE);
}
public void push(int val) {
stack.push(val);
minStack.push(Math.min(minStack.peek(), val));
}
public void pop() {
stack.pop();
minStack.pop();
}
public int top() {
return stack.peek();
}
public int getMin() {
return minStack.peek();
}
}
タイム: 95.54% を達成
メモリ: 48.09% で負けました
150. 逆ポーランド語表現の評価
質問の意味:
逆ポーランド記法で算術式を
tokens
表す 文字列の配列が与えられます 。この式を評価してください。式の値を表す整数を返します。
知らせ:
- 有効な演算子は
'+'
、、、'-'
および'*'
です'/'
。- 各オペランド (オペランド) には、整数または別の式を指定できます。
- 2 つの整数間の除算は、常に 0 に向かって切り捨てられます 。
- 式にはゼロによる除算演算はありません。
- 入力は、逆ポーランド表記で表現された算術式です。
- 答えとすべての中間計算結果は 32 ビット 整数として表現できます。
【入力例】 token=["2","1","+","3","*"]
[出力例] 9(2+1)*3=9
問題解決のアイデア:
逆ポーランド式は後置式とも呼ばれ、演算子が 2 つのオペランド、ab* --> a*b の後にあることを意味します。
1. スタックを使用して実装し、オペランドが見つかった場合はスタックにプッシュします。
2. 演算子 +-*/ が出現すると、スタックの先頭とサブスタックの先頭の値がポップアップされます。演算の順序はサブスタックの先頭とサブスタックの先頭であることに注意してください。演算子スタックの; 結果を計算した後、計算結果をスタックに格納する必要があります。
class Solution {
public int evalRPN(String[] tokens) {
Deque<Integer> num = new LinkedList<Integer>();
int a,b,temp;
for(String str : tokens){
//注意,存入数据的时候,将其转成int形。方便计算
if(isNumber(str)){
num.push(Integer.parseInt(str));
}else{
b = num.pop();
a = num.pop();
switch(str){
case "+":
num.push(a+b);
break;
case "-":
num.push(a-b);
break;
case "*":
num.push(a*b);
break;
case "/":
num.push(a/b);
break;
}
}
}
return num.peek();
}
public boolean isNumber(String str){
return !("+".equals(str) ||"-".equals(str) ||"*".equals(str) ||"/".equals(str));
}
}
タイム: 92.77% を達成
メモリ: 79.78% 上回る