java判斷有效的括號序列
需求:
給定一個字串所表示的括號序列,包含以下字元: '(', ')'
, '{'
, '}'
,'['
and']'
, 判定是否是有效的括號序列。
分析:
1、對於有效的括號序列,滿足下列特點:
1)有效的括號序列長度是不為0的偶數,所以字串長度為0或者奇數時就返回false
2)如果第一個字元是右括號或者最後一個字元是左括號,那麼不是有效括號序列,會返回false
上述1)和2)可以直接判斷不是有效括號序列,這樣就減少了記憶體以及時間開銷。比如對於"{(){"序列,如果不進行2)的判斷,可能需要開闢堆疊空間,判斷到最後才得出false的結論,但是如果一開始就判斷開頭和結尾是否滿足有效括號序列的條件,就可以不開闢堆疊空間,進而減少記憶體開銷,提高程式碼效率。
2、資料結構選用堆疊
堆疊是一種LIFO(後進先出)的資料結構。遍歷字串,將左括號推入堆疊,對於右括號,判斷棧頂元素與其是否匹配,如果不匹配就不有效,否則彈出棧頂元素,說明該層的括號已經判斷完畢,繼續遍歷字串進行判斷。遍歷之後,需要判斷堆疊是否為空,如果不是空的,說明左括號多於右括號,不有效,返回false,否則返回true。
3、java中的堆疊實現
1) Stack類
JDK1.0提供了Stack類,即堆疊類,有如下方法
boolean empty()//判斷堆疊是否為空 E push(E e)//將元素e推入棧頂 E peek()//獲取棧頂元素 E pop()//彈出棧頂元素 int search(Object obj)//此方法返回距堆疊頂部最近的出現位置到堆疊頂部的距離;堆疊中最頂部項的距離為 1。使用equals 方法比較o 與堆疊中的項。
2)Deque介面
Deque(Double ended queue雙端佇列)介面實現了提供LIFO堆疊操作的一系列更完整和更一致的set,應該優先使用Deque的子類,而非Stack,比如:
Deque<Integer> deq = new ArrayDeque<Integer>();
在將雙端佇列用作佇列時,將得到 FIFO(先進先出)行為。將元素新增到雙端佇列的末尾,從雙端佇列的開頭移除元素。從Queue介面繼承的方法完全等效於Deque方法;雙端佇列也可用作 LIFO(後進先出)堆疊。應優先使用此介面而不是遺留Stack
類。在將雙端佇列用作堆疊時,元素被推入雙端佇列的開頭並從雙端佇列開頭彈出。堆疊方法完全等效於Deque
ArrayDeque是Deque的子類,既可以實現堆疊,又可以實現佇列。ArrayDeque用作堆疊時,效率比Stack高,用作佇列時,效率比LinkedList高,所以一般使用ArrayDeque來實現堆疊和佇列的資料結構。
3)Deque介面方法摘要
a)判斷
boolean isEmpty()//判斷是否是空的
b)新增元素
void push(E e)//將元素e推入表示的堆疊棧頂
boolean offer(E e)//在雙端佇列尾部新增元素等價於offerLast()
boolean offerFirst(E e)//在雙端佇列頭部新增元素
boolean offerLast(E e)//在雙端佇列尾部新增元素
使用offer替換add方法
c)獲取元素
E peek()//獲取雙端佇列頭部元素,等價於peekFirst()
E peekFirst()//獲取雙端佇列頭部元素
E peekLast()//獲取雙端佇列尾部元素
使用peek替換get方法
d)刪除元素
E pop()//彈出棧頂元素
E poll()//獲取並移除佇列頭部元素,等價於pollFirst()
E pollFirst()
E pollLast()//獲取並移除雙端佇列尾部元素
使用poll代替remove
e)獲取元素個數
int size()
4)ArrayDeque
用作堆疊:push(E e) pop() peek()/peekFirst()
用作佇列:offer(E e)/offerLast(E e) poll() peek()
步驟:
1、判斷分析中的1)和2)條件,提高程式碼效率。如果返回false,程式結束,否則進行步驟2
2、建立堆疊,遍歷字串,如果是左括號,則推入堆疊中,如果是右括號,判斷堆疊是否是空的,如果是空的返回false,否則看棧頂元素是否和該右括號匹配,如果不匹配返回fasle,如果匹配就將棧頂彈出,繼續遍歷字串
3、字串遍歷結束,判斷堆疊是否是空的,如果不是空的,說明左括號數量大於右括號,不是有效括號序列,返回false,否則返回true
程式碼:
public class Solution {
/*
* @param s: A string
* @return: whether the string is a valid parentheses
*/
public boolean isValidParentheses(String s) {
// write your code here
//如果字串為null或者長度是奇數或者0,那麼就不是有效括號,就返回false
//如果字串的頭部是右括號或者尾部是左括號,返回fasle
int len = s.length();
if(s == null || len == 0 || len % 2 != 0)
{
return false;
}
char start = s.charAt(0);
char end = s.charAt(len - 1);
if(start == '}' || start == ')' || start == ']')
{
return false;
}
if(end == '{' || end == '(' || end == '[')
{
return false;
}
//建立堆疊
Deque<Character> stack = new ArrayDeque<Character>();
//遍歷字串,如果是左括號就新增到堆疊中,如果是右括號,看是否和棧頂元素匹配,匹配就pop棧頂元素,不匹配就返回false,如果遍歷到最後一個元素,並且和棧頂元素匹配即可返回true,否則fasle
for(int i = 0; i < len; i++)
{
char ch = s.charAt(i);
//如果是左括號就直接新增進堆疊
if(ch == '{' || ch == '(' || ch == '[')
{
stack.push(ch);
}
//如果是右括號,進行匹配判斷
else if(ch == '}' || ch ==')' || ch ==']')
{
if(stack.isEmpty())
{
return false;
}
else
{
char peek = stack.peek();
if(isMatch(peek, ch))
{
stack.pop();
}
else
{
return false;
}
}
}
}
//判斷堆疊是否是空的,如果是空的,就是
if(stack.isEmpty())
{
return true;
}
return false;
}
//判斷是否是匹配的括號對
public boolean isMatch(char c1, char c2)
{
return (c1 == '{' && c2 == '}' || c1 == '(' && c2 == ')' || c1 == '[' && c2 == ']')? true: false;
}
}