1. 程式人生 > >LeetCode棧的基礎操作系列問題詳細總結

LeetCode棧的基礎操作系列問題詳細總結

LeetCode中考察棧的基礎操作的問題有20. Valid Parentheses,71. Simplify Path,150. Evaluate Reverse Polish Notation等,本文對這三個題進行詳細的解析。

棧是一種特殊的線性表,僅能線上性表的一端操作,棧頂允許操作,棧底不允許操作是一種先進後出(LIFO)的資料結構。其最基礎的操作包括建立一個棧(Stack())、入棧(push(E item))和出棧(pop())。下面是相關的Java API。
建立棧
push()
pop()
接下來使用這些基礎操作來解決實際問題:

LeetCode 20. Valid Parentheses

Description:

Given a string containing just the characters ‘(’, ‘)’, ‘{’, ‘}’, ‘[’ and ‘]’, determine if the input string is valid.

An input string is valid if:

  1. Open brackets must be closed by the same type of brackets.
  2. Open brackets must be closed in the correct order.

Note that an empty string is also considered valid.

Example 1:

Input: "()"
Output: true

Example 2:

Input: "()[]{}"
Output: true

Example 3:

Input: "(]"
Output: false

Example 4:

Input: "([)]"
Output: false

Example 5:

Input: "{[]}"
Output: true

思路解析:

題意是給定一個包含括號的字串,判斷是否可以匹配。

本題考查棧的基礎應用,可以利用棧的入棧、出棧操作完成解答。

對字串的每個字元進行遍歷,如果是左括號,進行入棧操作;

這一步完成需要判斷一下棧是否為空,也就是說如果剛開始的是右括號的話,明顯是不可匹配的,直接返回false;

上面已經判斷了不是左括號,接著就要判斷右括號和棧頂的括號(執行pop()操作)是否匹配,不匹配直接返回false;

最後注意遍歷完成以後,如果全部匹配的話,push()和pop()操作是成對出現的,返回的是stack.isEmpty(),這樣也可以保證了題目中“Note that an empty string is also considered valid”,空串也認為是可以匹配的。

程式碼如下:

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(int i = 0 ; i < s.length() ; i ++){
            char c = s.charAt(i);
            if(c == '(' || c == '[' || c == '{'){
                stack.push(c);
            } else{
                if(stack.isEmpty()){
                    return false;
                }
                char topChar = stack.pop();
                if(c == ')' && topChar != '(')
                    return false;
                if(c == ']' && topChar != '[')
                    return false;
                if(c == '}' && topChar != '{')
                    return false;
            }
        }
        return stack.isEmpty();
    }
}

LeetCode 71. Simplify Path

Description:

Given an absolute path for a file (Unix-style), simplify it.

For example,
path = “/home/”, => “/home”
path = “/a/./b/…/…/c/”, => “/c”
path = “/a/…/…/b/…/c//.//”, => “/c”
path = “/a//b////c/d//././/…”, => “/a/b/c”

In a UNIX-style file system, a period (’.’) refers to the current directory, so it can be ignored in a simplified path. Additionally, a double period ("…") moves up a directory, so it cancels out whatever the last directory was. For more information, look here: https://en.wikipedia.org/wiki/Path_(computing)#Unix_style

Corner Cases:

  • Did you consider the case where path = “/…/”?
    In this case, you should return “/”.
  • Another corner case is the path might contain multiple slashes ‘/’
    together, such as “/home//foo/”. In this case, you should ignore
    redundant slashes and return “/home/foo”.

思路解析:

本題題意是簡化路徑,考查棧的基礎操作。

具體操作是把路徑看做是由一個或多個"/“分割開的多個子字串,把它們分別提取出來進行處理。如果是”.“的情況直接去掉,是”…“時刪掉它上面挨著的一個路徑;如果是空的話返回”/",如果有多個"/"只保留一個。

對應於棧,如果是"…",出棧;如果不是".“或者”…",也不為空,入棧。

程式碼如下:

class Solution {
    public String simplifyPath(String path) {
        Stack<String> stack = new Stack<>();
        String[] p = path.split("/");
        for (String t : p) {
            if (!stack.isEmpty() && t.equals("..")) {
                stack.pop();
            } else if (!t.equals(".") && !t.equals("") && !t.equals("..")) {
                stack.push(t);
            }
        }
        List<String> list = new ArrayList(stack);
        return "/" + String.join("/", list);
    }
}

LeetCode 150. Evaluate Reverse Polish Notation

Description:

Evaluate the value of an arithmetic expression in Reverse Polish Notation.

Valid operators are +, -, *, /. Each operand may be an integer or another expression.

Note:

  • Division between two integers should truncate toward zero.
  • The given RPN expression is always valid. That means the expression
    would always evaluate to a result and there won’t be any divide by
    zero operation.

Example 1:

Input: ["2", "1", "+", "3", "*"]
Output: 9
Explanation: ((2 + 1) * 3) = 9

Example 2:

Input: ["4", "13", "5", "/", "+"]
Output: 6
Explanation: (4 + (13 / 5)) = 6

Example 3:

Input: ["10", "6", "9", "3", "+", "-11", "*", "/", "*", "17", "+", "5", "+"]
Output: 22
Explanation: 
  ((10 * (6 / ((9 + 3) * -11))) + 17) + 5
= ((10 * (6 / (12 * -11))) + 17) + 5
= ((10 * (6 / -132)) + 17) + 5
= ((10 * 0) + 17) + 5
= (0 + 17) + 5
= 17 + 5
= 22

思路解析:

本題是要計算逆波蘭表示式的值,主要考查棧的基礎應用,入棧和出棧操作。

具體做法:從左至右掃描表示式,遇到數字時,將數字壓入堆疊,遇到運算子時,彈出棧頂的兩個數,進行運算(次頂元素 op 棧頂元素),並將結果入棧;重複上述過程直到表示式最右端,得出的值即為表示式的結果。

更多關於逆波蘭表示式可以參考https://blog.csdn.net/u014116780/article/details/82964481

程式碼如下:

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<Integer>();
        for(int i=0;i<tokens.length;i++){
            if(isInteger(tokens[i])){
                stack.push(Integer.parseInt(tokens[i]));
            }else{
                int num1 = stack.pop();
                int num2 = stack.pop();
                int res = operate(tokens[i],num1,num2);
                stack.push(res);
            }
        }
        return stack.pop();
    }
    
    public boolean isInteger(String string){
        try{
            if(Integer.parseInt(string)>=Integer.MIN_VALUE && Integer.parseInt(string)<=Integer.MAX_VALUE){
                return true;
            }
        }catch(Exception e){
            return false;
        }
        return false;
    }
    
    public int operate(String operation, int num1, int num2){
        if("+".equals(operation)){
            return num1 + num2;
        }else if("*".equals(operation)){
            return num1 * num2;
        }else if("/".equals(operation)){
            return num2 / num1;
        }else if("-".equals(operation)){
            return num2 - num1;
        }else{
            throw new RuntimeException("operation error!");
        }
    }
}