題目1:判斷一個序列是否可能爲出棧序列
輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否可能爲該棧的彈出順序。假設壓入棧的所有數字均不相等。例如序列1,2,3,4,5是某棧的壓入順序,序列4,5,3,2,1是該壓棧序列對應的一個彈出序列,但4,3,5,1,2就不可能是該壓棧序列的彈出序列。(注意:這兩個序列的長度是相等的)
劍指offer 22題:https://www.nowcoder.com/practice/d77d11405cc7470d82554cb392585106
解答
雙指針:i 指向pushV的元素,j 指向popV的元素。
新建一個棧,將數組pushV逐個入棧,
當棧頂元素等於popV [ j ] 時 (while循環,不是if),就將其出棧,同時 j 後移
當遍歷完pushV時,判斷棧是否爲空,若爲空則返回true。
時間複雜度O(n)
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
int n = pushV.size();
if(n != popV.size()) return false; // 包含了有一個數組爲空的情況
// 後面代碼能夠應對2個數組都爲空的情況,故不單獨考慮
stack<int> st;
int j = 0;
for(int i=0; i<n; i++){
st.push(pushV[i]);
while(j<n && st.top() == popV[j]){
st.pop();
j++;
}
}
return st.empty();
}
題目2
給定一個長度爲n的入棧序列(不重複),打印全部可能的出棧序列
解答
全部可能的出棧序列數爲卡特蘭數:
方法1:枚舉所有排列結果,然後調用題目1的函數判斷。時間複雜度O(n! * n)
方法2:只枚舉可能的出棧序列,時間複雜度O(Cn).
當我們模擬時會發現,除開始時必須將第一個元素入棧外,其他時候面臨着出棧或入棧新元素兩種情況。可用遞歸實現。
int cnt = 0;
void FindPopSeqs(deque<int> in,vector<int> out,stack<int> Stack)
{
if(in.size() == 0) { // 遞歸邊界
while(!Stack.empty()){
out.push_back(Stack.top());
Stack.pop();
}
for(int i=0; i<out.size(); i++)
cout<<out[i]<<" ";
cout<<endl;
cnt++;
return;
}
// 有2個選擇:入棧或出棧(順序可互換)
// 1.入棧
Stack.push(in.front());
in.pop_front();
FindPopSeqs(in, out, Stack);
// 恢復(關鍵點)
in.push_front(Stack.top());
Stack.pop();
// 2.出棧
if(Stack.size() > 0) {
out.push_back(Stack.top());
Stack.pop();
FindPopSeqs(in, out, Stack);
// 恢復(可忽略這步,因爲參數都是值傳遞且後面已無遞歸)
//Stack.push(out.back());
//out.pop_back();
}
}
int main(){
vector<int> in{1,2,3}, out;
stack<int> Stack;
deque<int> _in(in.begin(), in.end()); // 也可用list,要在兩端插入/刪除
FindPopSeqs(_in, out, Stack);
cout<<cnt<<endl;
return 0;
}