二、佇列,棧,堆(小象)
225.用佇列實現棧
思考:佇列的特性先進先出,棧後進先出,所以用一個臨時temp_queue來新增新的元素,再把所有元素都匯入到原始的queue之中,那麼刪除就正好是最新插入的元素了。
class MyStack { public: /** Initialize your data structure here. */ MyStack() { } queue<int> obj; /** Push element x onto stack. */ void push(int x) { queue<int> temp_queue; temp_queue.push(x); while(!obj.empty()){ temp_queue.push(obj.front()); obj.pop(); //一開始沒有pop導致超時了,把棧和佇列想的和連結串列一樣 //以為會覆蓋值,後來想想不一樣,它直接向後繼續添加了。 } while(!temp_queue.empty()){ obj.push(temp_queue.front()); temp_queue.pop(); } } /** Removes the element on top of the stack and returns that element. */ int pop() { int x = obj.front(); obj.pop(); return x; } /** Get the top element. */ int top() { return obj.front(); } /** Returns whether the stack is empty. */ bool empty() { return obj.empty(); } }; /** * Your MyStack object will be instantiated and called as such: * MyStack obj = new MyStack(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.top(); * bool param_4 = obj.empty(); */
232.用棧實現佇列
class MyQueue { public: /** Initialize your data structure here. */ MyQueue() { } stack<int> data; stack<int> temp_stack; /** Push element x to the back of queue. */ void push(int x) { while(!data.empty()){ temp_stack.push(data.top()); data.pop(); } temp_stack.push(x); while(!temp_stack.empty()){ data.push(temp_stack.top()); temp_stack.pop(); } } /** Removes the element from in front of queue and returns that element. */ int pop() { int x = data.top(); data.pop(); return x; } /** Get the front element. */ int peek() { return data.top(); } /** Returns whether the queue is empty. */ bool empty() { return data.empty(); } }; /** * Your MyQueue object will be instantiated and called as such: * MyQueue obj = new MyQueue(); * obj.push(x); * int param_2 = obj.pop(); * int param_3 = obj.peek(); * bool param_4 = obj.empty(); */
155.最小棧
思考:如果用一個元素minOfStack來儲存最小值,在新增的時候沒有問題;可是在刪除的時候就會存在恰好是最小的那個元素唄刪除了,那麼此時最小值仍然是被刪除的元素就發生了錯誤。並且如果是用遍歷棧來查詢最小值,那麼時間複雜度就不是O(1)。所以可以構造一個臨時儲存最小值的棧,棧中每一個位正好對應當前情況下棧的最小值。
程式設計的技巧:當一個操作無論在條件發生不發生的時候都會執行,可以放在條件語句之外。
例如:當前新增元素x如果大於min_stack_top,就把x賦值為min_stack_top;如果小於則直接新增;因為無論小於還是大於都要新增一個新的元素到min_stack_top。
class MinStack {
public:
/** initialize your data structure here. */
MinStack() {
}
stack<int> stack_data;
stack<int> min_stack;
void push(int x) {
stack_data.push(x);
if(min_stack.empty()){
min_stack.push(x);
}
else{
if(x > min_stack.top()){
x = min_stack.top() ; //關鍵!
}
min_stack.push(x);
}
}
void pop() {
stack_data.pop();
min_stack.pop();
}
int top() {
return stack_data.top();
}
int getMin() {
return min_stack.top();
}
};
/**
* Your MinStack object will be instantiated and called as such:
* MinStack obj = new MinStack();
* obj.push(x);
* obj.pop();
* int param_3 = obj.top();
* int param_4 = obj.getMin();
*/
例題4.合法的出棧序列
思考:使用棧和佇列來模擬入棧和出棧的過程。
用佇列來儲存出棧序列,然後用棧來模擬出棧入棧的過程,因為出戰序列的第一位肯定是棧中的top元素,所以每次只用對比top元素和出戰序列的front,兩者相等就同時彈出,否則就再入棧。
#include<stack>
#include<queue>
bool check_is_valid_order(queue<int> &order)
{
stack<int> s;
int num = order.size();
for(int i =1 ;i <= num;i++){
s.push(i);
// while(order.front()==s.top()) 如果棧已經彈空了,佇列也是空了,都是NULL,繼續彈出就會出錯,所以修改下列。
while(order.front()==s.top()&&!s.empty()){
s.pop();
oder.pop();
}
}
if(!s.empty()){
return false;
}
return true;
}
224.基礎計數器
思考:畫出有窮狀態機就可以解決了。
class Solution {
public:
void compute(stack<int> &numbers,stack<char> &operation){
if(numbers.size()<2){
return ;
}
int num2 = numbers.top();
numbers.pop();
int num1 = numbers.top();
numbers.pop();
if(operation.top() == '+'){
numbers.push(num1 + num2);
}
else if(operation.top() == '-') {
numbers.push(num1 - num2);
}
operation.pop();
}
int calculate(string s) {
static const int BEGIN_STATE = 0;
static const int NUMBER_STATE = 1;
static const int OPERATOR_STATE = 2;
stack<int> numbers_stack;
stack<char> operation_stack;
int number = 0;
int STATE = BEGIN_STATE;
int compute_flag = 0;
//遇到數字和+-的時候才有用 才需要推格操作
for(int i = 0;i<s.size();i++){
if(s[i] == ' '){
continue;
}
switch(STATE){
case BEGIN_STATE:
if(s[i]>='0' && s[i]<='9'){
STATE = NUMBER_STATE;
}
else{
STATE = OPERATOR_STATE;
}
i--;
break;
case NUMBER_STATE:
if(s[i]>='0' && s[i]<='9'){
number = number * 10 + s[i] - '0';
}
//'123'字串在把他變成了數字之後狀態仍然沒有改變。
//所以判斷compute_flag
else{
numbers_stack.push(number);
if(compute_flag==1){
compute(numbers_stack,operation_stack);
}
//如果字串第一個'123'此時compute_flag = 0 前面沒有數字不能計算。
number = 0;
i--;
STATE = OPERATOR_STATE;
}
break;
case OPERATOR_STATE:
if(s[i]== '+'||s[i] == '-'){
operation_stack.push(s[i]);
compute_flag = 1;
}
else if(s[i]=='('){
STATE = NUMBER_STATE;
compute_flag = 0;
}
else if(s[i]>='0' && s[i]<='9'){
STATE = NUMBER_STATE;
i--;
}
else if(s[i]==')'){
compute(numbers_stack,operation_stack);
}
break;
}
}
if(number!=0){
numbers_stack.push(number);
compute(numbers_stack,operation_stack);
}
if(number==0 && numbers_stack.empty()){
return 0;
}
return numbers_stack.top();
}
};
STL優先順序佇列構造堆
priority_queue<int> heap; //構造預設堆
priority_queue<int,vector<int>,greater<int>> small_heap; //構造預設最小堆
priority_queue<int,vector<int>,less<int>> big_heap; //構造預設最大堆
int test[] = {61,2,4,5,6,7,9,0};
vector<int> vec(test,test+8);
for( unsigned int i = 0;i < vec.size();i++){
big_heap.push(vec.at(i));
}
for(unsigned int i = 0;i < vec.size();i++){
cout<<big_heap.top()<<endl;
big_heap.pop();
}
遇到的問題和積累:
1error “<”: 有符號/無符號不匹配
答:”detector 是一個Vector容器 ,detecot.size() 在容器說明中 被定義為: unsigned int 型別, 而j是int 型別,所以會出現: 有符號/無符號不匹配警告,修改int i -->> unsigned int / size_t
2.error: error C2065: “cout”: 未宣告的識別符號 error C2065: “endl”: 未宣告的識別符號
答:沒#include<iostream> ,之後再using namespace std
3.vector 兩種訪問 1、陣列 2、 vec.at(i) //這種會檢測訪問越界
4.big_heap[8](61,6,9,2,5,4,7,0) 這個排序和按照二叉樹 而不是陣列的排序 pop()檢查過才知道
215.陣列中第K個最大的元素
思考: 第k大 用最小堆來處理,直接輸出堆頂元素,保證最小堆有k個元素,那麼堆頂元素是第k個元素中最小的,就是整個vector中第k大的。這裡我一開始寫的想用兩個for迴圈,第一次是儲存k個元素的堆;第二次是和堆頂元素進行比較。後來看了別人的程式碼,哇,深感自己太不會變通了。直接一次迴圈就可以了!~
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
priority_queue<int,vector<int>,greater<int>> small_heap;
for(int i = 0; i <nums.size();i++){
if(i<k){
small_heap.push(nums[i]);
}
else if(nums[i] > small_heap.top()){
small_heap.pop();
small_heap.push(nums[i]);
}
}
return small_heap.top();
}
};
295.資料流的中位數
思考:
class MedianFinder {
public:
/** initialize your data structure here. */
MedianFinder() {
}
//如果你用了else if 語句,當你條件滿足時就不會再往下繼續判斷條件了;
//而if語句會把每一個條件都判斷一下。
//兩個約束:1、最大堆的堆頂小於最小堆的堆頂,這樣就把資料流中間的數字找到了
//2、兩個堆之間的數目相差不超過1
void addNum(int num) {
if(big_heap.empty()){
big_heap.push(num);
return ;
}
if(small_heap.size()==big_heap.size()){
//既然要儲存到big_heap,那麼肯定是和big_heap的堆頂比較,只要小於就說明屬於這一半。
if(num < big_heap.top()){
big_heap.push(num);
}
else {
small_heap.push(num);
}
}
else if(small_heap.size() > big_heap.size()){
if(num >= small_heap.top()){
big_heap.push(small_heap.top());
small_heap.pop();//又當做連結串列直接覆蓋了,這裡如果你不把top()彈出來,
//那麼你這個堆裡面就多了一個元素呀。
small_heap.push(num);
}
else{
big_heap.push(num);
}
}
else if(small_heap.size() < big_heap.size()){
if(num <=big_heap.top()){
small_heap.push(big_heap.top());
big_heap.pop();
big_heap.push(num);
}
else{
small_heap.push(num);
}
}
}
double findMedian() {
if(small_heap.size()==big_heap.size()){
return (small_heap.top() + big_heap.top())/2;
}
else if(small_heap.size() > big_heap.size()){
return small_heap.top();
}
return big_heap.top();
}
priority_queue<double,vector<double>,greater<double>> small_heap;
priority_queue<double,vector<double>,less<double> > big_heap;
//最小堆和最大堆定義反了!!!debug半天!
};
總結:這個程式碼真調了無數次。。。
1、第一個錯誤,當small_heap 和 big_heap 中的數 相等的時候,就只用判斷num和small_heap.top()和big_heap.top()大小,如果大於small_heap.top(),肯定屬於small_heap,直接插入,反之亦然。
2、優先佇列 priority_queue<double,vector<double>,greater<double>> small_heap;定義的時候出錯了,第一個把資料型別弄成了int,導致輸出的中位數出錯了;第二個是排序錯了,把兩個正好弄反了,應該是最大堆,對應的遞減啊!最小堆對應的遞增啊!想下就清楚了!~!~