【算法系列 二】Stack

棧應用的場景:
1.括號問題
2.後綴表達式
3.深度優先遍歷
4.保存現場 java

1. 給定字符串,僅由「()[]{}」六個字符組成。設計算法,判斷該字符串是否有效。 算法

    括號必須以正確的順序配對,如「()」、「()[]{}」是有效的,但"([)]"是無效的(Leetcode 20)。 lua

思想就是碰到左括號壓棧,右括號出棧,而後判斷彈出的元素是否是一對,最後棧爲空則是真的。 spa

代碼以下: .net

public class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<Character>();
		boolean isvalid = true;
		char[] c = s.toCharArray();
		char temp;
		for (int i = 0; i < c.length; i++)
		{
			switch (c[i])
			{
			case '(':
				stack.push(c[i]);
				break;
			case ')':
				if(stack.isEmpty())
				{
					isvalid = false;
				}else {
					temp = stack.pop();
					if (temp != '(')
					{
						isvalid = false;
					}
				}
				break;
			case '[':
				stack.push(c[i]);
				break;
			case ']':
				if(stack.isEmpty())
				{
					isvalid = false;
				}else {
					temp = stack.pop();
					if (temp != '[')
					{
						isvalid = false;
					}
				}
				break;
			case '{':
				stack.push(c[i]);
				break;
			case '}':
				if(stack.isEmpty())
				{
					isvalid = false;
				}else
				{
					temp = stack.pop();
					if (temp != '{')
					{
						isvalid = false;
					}
				}
				break;
			default:
				break;
			}
		}
		if(isvalid)
		{
			if(!stack.isEmpty())
			{
				isvalid = false;
			}
		}
		return isvalid;
    }
}

順便提一下:關於括號匹配問題,還有一個括號的組成個數問題,給定n組括號,問有多少種合法表達式,也是應用棧。(參kao這裏,算法篇第8題 設計


2. 給定字符串,僅包含"("和")",它可能不是全匹配的,設計算法找出最長匹配的括號子串,返回該子串的長度。Leetcode 32 code

For example: blog

")()())":4 token

"()(()":2  leetcode

"()(())":6

看到括號問題,第一反應就是用棧,一個簡單的思想就是與第一問同樣,每次匹配成功,則把成功的位置作個記號,最後看記號的最長子串是多少便可好比"()(()"記號就能夠是"YYNYY"。要遍歷兩次,時間複雜度爲O(2n) = O(n)

public class Solution {
    public int longestValidParentheses(String s) {
        char[] c = s.toCharArray();
		boolean[] b = new boolean[c.length];
		Stack<Integer> stack = new Stack<Integer>();
		for (int i = 0; i < c.length; i++)
		{
			if (c[i] == '(')
			{
				stack.push(i);
			}
			else if (c[i] == ')' && !stack.isEmpty())
			{
				int index = stack.pop();
				b[index] = true;
				b[i] = true;
			}
		}
		int maxLength = 0;
		int length = 0;
		for (int i = 0; i < c.length; i++)
		{
			if (b[i])
			{
				length++;
			}
			else
			{
				length = 0;
			}
			maxLength = maxLength > length ? maxLength : length;
		}
		return maxLength;
    }
}

以上的方法須要遍歷兩次,有沒有隻遍歷一次的方法呢?

咱們定義兩個變量,start=-1,最大匹配長度ml=0

變量i爲當前掃描的字符

棧內只多是"(",碰到"("就壓棧,碰到")"就出棧。因爲咱們要計算的最長匹配長度,因此壓棧的是"("的下標方便計算長度。

在任什麼時候候,只要棧不空,那麼存在棧裏的元素的意義就是當前還沒有被匹配的‘(’。由於若匹配,咱們會進行pop操做,因此在進行一次匹配後,咱們若判斷棧不空,那就說明至少棧頂的元素是沒有匹配的,而這個沒有匹配的棧頂‘(’,極有可能到最後也得不到匹配,因此咱們這時要及時的更新最大長度,那麼當前的已經匹配的長度是多少呢?是當前訪問元素的index - 棧頂元素的值。若進行一次匹配操做後,發現棧爲空了,這說明什麼呢?說明是處於連續的匹配中,這時咱們也要跟新最大長度,由於極有可能在之後就不匹配了,當前這個匹配的最大結果要進行保留。可是此時,咱們只有當前遍歷元素的下標,另一個值是什麼呢?也就是減數是多少呢?因此咱們還須要定義一個變量start,用來表示每一次連續匹配的起始點,咱們用當前的下標- start來表示當前的最大長度。那麼若當前遍歷的元素爲‘)’,且此時棧爲空,說明什麼呢?說明在此以前,就沒有多餘的‘(’,說明這就是個坑,是個不匹配的點,此時咱們要作些什麼呢?簡單的將該字符跳過,去處理下一個字符嗎?回頭看看咱們剛纔分析中,涉及到了一個連續匹配的起始點問題,對,咱們要更改這個連續匹配的起始點,令其等於當前處理的‘)’字符的位置。

因此整體流程以下:

若是爲"(",壓棧

若是爲")":

棧爲空:start = i

棧不爲空:出棧

此時棧爲空:ml = i -start

棧不爲空:ml = i - 棧頂元素

代碼:

public class Solution {
    public int longestValidParentheses(String s) {
        char[] c = s.toCharArray();
		int start = -1;
		int ml = 0;
		Stack<Integer> stack = new Stack<Integer>();
		for (int i = 0; i < c.length; i++)
		{
			if (c[i] == '(')
			{
				stack.push(i);
			}
			else
			{
				if (stack.isEmpty())
				{
					start = i;
				}
				else
				{
					stack.pop();
					if (stack.isEmpty())
					{
						ml = (i - start) > ml ? (i - start) : ml;
					}
					else
					{
						ml = (i - stack.peek()) > ml ? (i - stack.peek()) : ml;
					}
				}

			}
		}
		return ml;
    }
}

時間複雜度O(n)


3. 計算給定的後綴表達式值,有效操做只有+-*/,每一個操做數都是整數。(Leetcode 150)

Some examples:

["2", "1", "+", "3", "*"] -> ((2 + 1) * 3) -> 9
["4", "13", "5", "/", "+"] -> (4 + (13 / 5)) -> 6
除了括號問題,後綴表達式也是一個經常使用棧來處理的問題。碰到數字就壓棧,碰到操做符彈出兩個數字計算後,結果再壓棧。

代碼:

public class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<Integer>();
		int res = 0;
		int a,b;
		for (int i = 0; i < tokens.length; i++)
		{
			switch (tokens[i])
			{
			case "+":
				a = stack.pop();
				b = stack.pop();
				res = a + b;
				stack.push(res);
				break;
			case "-":
				a = stack.pop();
				b = stack.pop();
				res = b - a;
				stack.push(res);
				break;
			case "*":
				a = stack.pop();
				b = stack.pop();
				res = b * a;
				stack.push(res);
				break;
			case "/":
				a = stack.pop();
				b = stack.pop();
				res = b / a;
				stack.push(res);
				break;
			default:
				stack.push(Integer.parseInt(tokens[i]));
				res = Integer.parseInt(tokens[i]);
				break;
			}
		}
		return res;
    }
}

注意相似["18"]這種狀況,須要返回18。



系列:

【算法系列 一】 Linked List

【算法系列 二】 Stack

【算法系列 三】 Quene

【算法系列 四】 String

相關文章
相關標籤/搜索