【leetcode刷题记#week02】栈、队列、双端队列

10 篇文章 0 订阅
5 篇文章 0 订阅
20.有效的括号

检测一段字串序列中的有效括号

栈方法(C++)
  1. 创建一个栈结构,

    1. 若是左括号,则入栈
    2. 若是右括号,则检测栈顶是否是相应左括号
  2. 细节:

    1. 检测输入长度,若是0,直接返回true;若长度为奇数,返回false

       if(!s.length()) return true;
       if(s.length%2=1) return false;
      
    
    
  3. 建立散列表(方便检测)

      unordered_map<char, char> pairs = {
                {']','['},
                {'}','{'},
                {')','('}    
            };
    
    1. 检测是否是右括号

       if(pairs.count(c))
      
    2. 别忘了检测完出栈哦

    3. 最后检验栈是否为空

      return stk.empty();
      
源码(map方法
class Solution {
public:
    bool isValid(string s) {

        if(!s.length()) {
            return true;
        }
        
        unordered_map<char, char> pairs = {
            {']','['},
            {'}','{'},
            {')','('}
            
        };

        stack<char> stk;


        for(char c: s) {
            
            if(pairs.count(c)) {
                
                if(stk.empty() || stk.top()!=pairs[c]) {
                    return false;
                }
                stk.pop();

            }
            else {
                stk.push(c);
            }
        }
        return stk.empty();

    }
};
源码(switch方法
    class Solution {
    public:
        bool isValid(string s) {

            if(s.empty()) return true;
            if(s.size()%2==1) return false;
            
            stack<char> paren;
            for (char& c : s) {
                switch (c) {
                    case '(': 
                    case '{': 
                    case '[': paren.push(c); break;
                    case ')': if (paren.empty() || paren.top()!='(') return false; else paren.pop(); break;
                    case '}': if (paren.empty() || paren.top()!='{') return false; else paren.pop(); break;
                    case ']': if (paren.empty() || paren.top()!='[') return false; else paren.pop(); break;
                    default: ; // pass
                }
            }
            return paren.empty() ;
        }
    };
155.最小栈

设计一个可以在 O ( 1 ) O(1) O(1) 时间复杂度内找到栈内最小元素的栈结构

双栈方法
  • 再开一个栈,名为最小栈,与数据栈并行操作,不同:
  1. push时,最小栈只压入当前最小元素
  2. 两栈一起pop。
  3. getMin直接去最小栈查询。
  • 细节

    • 官方题解很憨,最小栈不管什么情况都压入,这样会多出很多重复最小元素,浪费空间

      min_stack.push(min(min_stack.top(), x));
      
    • 节省空间,在push时做一个判断,利用getMin方法与待入元素做比较,节省最小栈的空间

       void push(int x) {
              data_stack.push(x);
              if(min_stack.empty() || x<=getMin())
                   min_stack.push(x); 
          }
      
    • 最小栈pop时判断,不pop

      void pop() {
              if(data_stack.top()==getMin())
                  min_stack.pop();
              data_stack.pop();
          }
      
双栈法源码
class MinStack {
public:
    /** initialize your data structure here. */

    // Two Stacks Method 
    stack<int> data_stack;
    stack<int> min_stack;

    MinStack() {
        min_stack.push(INT_MAX);
    }
    
    void push(int x) {
        data_stack.push(x);
        if(min_stack.empty() || x<=getMin())
             min_stack.push(x); 
    }
    
    void pop() {
        
        if(data_stack.top()==getMin())
            min_stack.pop();
        data_stack.pop();
    }
    
    int top() {
        return data_stack.top();
    }
    
    int getMin() {
        return min_stack.top();
    }
};
Pair 法

本方法只用一个栈,但是扩大存入的元素大小

int ----> { int, min_int }

每个元素的second值记录当前最小值

题解来源:fuxuemingzhu

class MinStack {
public:
    /** initialize your data structure here. */
    MinStack() {
    }
    
    void push(int x) {
        if (st.size() == 0) {
            st.push({x, x});
        } else {
            st.push({x, min(x, st.top().second)});
        }
    }
    
    void pop() {
        st.pop();
    }
    
    int top() {
        return st.top().first;
    }
    
    int getMin() {
        return st.top().second;
    }
private:
    stack<pair<int, int>> st;
};
622.设计循环队列 & 641. 设计双向循环队列

循环队列,故名思义,就是头尾相接的数组/链表等基础数据结构 为基础实现的队列结构

链表方法

不如数组的下标可以利用复杂的数关系那样的 tricky

链表法在实现时,是比较容易思考的,因为链表的基本操作完全是是线性的

以下是我个人思考链表题时的过程:(分函数考虑)

Created with Raphaël 2.2.0 开始 考虑一般情况 画图 考虑边界情况 再画图 写代码
细节:
  1. 注意边界的检查,即插入第一个元素时,控制首尾指针的行为

  2. 插入顺序:

    newnode ->next = temp;
    rear -> next = head;           
    
源码:
struct LinkedNode {
    int val;
    LinkedNode *next;

    LinkedNode(int val){
        val = val;
        next = nullptr;
    }
};

class MyCircularQueue {

    // This implementation is based on Linked List
private:
    int size,capacity;
    ListNode* head,*rear;
    
public:
    /** Initialize your data structure here. Set the size of the queue to be k. */
    MyCircularQueue(int k) {
        // the head as a dummy node
        size = 0;
        head =nullptr;
        
        rear = nullptr;
        
        capacity = k; 
    }
    
    /** Insert an element into the circular queue. Return true if the operation is successful. */
    bool enQueue(int value) {
        if(!isFull()) {

                ListNode* newnode =new ListNode(value), 
                *temp = head;

            		if(isEmpty()) {
                    rear = newnode;
                }

                head = newnode;
                newnode ->next = temp;
                rear -> next = head;
                
                size++;

                return true;
        }
        
        return false;

    }
    
    /** Delete an element from the circular queue. Return true if the operation is successful. */
    bool deQueue() {
        if(!isEmpty()) {
            ListNode* temp = head;
          
           while(temp->next !=rear) {
               temp= temp->next;
           }

            //kill
            temp ->next = head;
            rear = temp;

            size--;
            return true;

        }
        return  false;
        
    }
    
    /** Get the front item from the queue. */
    int Front() {
       return isEmpty()? -1 : this->rear->val;
    }
    
    /** Get the last item from the queue. */
    int Rear() {
        return isEmpty()? -1 : this->head->val;
    }
    
    /** Checks whether the circular queue is empty or not. */
    bool isEmpty() {
        return size == 0;
    }
    
    /** Checks whether the circular queue is full or not. */
    bool isFull() {
        return size == capacity;
    }
};


用链表设计Deque
  • 第一次想着:是不是把上面那道题的代码copy过来就行了,然而我过于天真,有以下几点问题:

    • 插入第一个元素:要使得头尾指针同时指向一个元素。
    if(isEmpty()) {
     	head = newnode;
       rear = newnode;            
    }
    
    • 删除第一个元素:要恢复头尾指针到空指针:
     if(rear == head) {
        rear = nullptr;
        head = nullptr;
        size--;
        return true;
       }
    
    • 临时指针到判空(前后插入都要,这里只给出前插入)
    bool insertFront(int value) {
    	if(!isFull()) {
    
                    LinkedNode* newnode = new LinkedNode(value),
                    *temp = head;
    
                    if(isEmpty()) {
                        head = newnode;
                        rear = newnode;
                    }
    
    
                    head = newnode;
       							// 必须判空,不然前插入后插入会使得循环链表断开
                    if(temp) newnode ->next = temp;
                    rear -> next = head;
                    
                    size++;
    
                    return true;
            }
    }
    
源码
struct LinkedNode {
    int val;
    LinkedNode *next;
   

    LinkedNode(int val){
        this->val = val;
        next = nullptr;
       
    }
};

class MyCircularDeque {
private:
    LinkedNode* head,*rear;
    int size,capacity;

public:
    /** Initialize your data structure here. Set the size of the deque to be k. */

    MyCircularDeque(int k) {
       
        head = nullptr;
        rear = nullptr;
        size = 0;
        capacity = k;
    }
    
    /** Adds an item at the front of Deque. Return true if the operation is successful. */
    bool insertFront(int value) {
        
        if(!isFull()) {

                LinkedNode* newnode = new LinkedNode(value),
                *temp = head;

                if(isEmpty()) {
                    head = newnode;
                    rear = newnode;
                }


                head = newnode;
          			// 必须判空,不然前插入后插入会使得循环链表断开
                if(temp) newnode ->next = temp;
                rear -> next = head;
                
                size++;

                return true;
        }
        
        return false;
    }
    
    /** Adds an item at the rear of Deque. Return true if the operation is successful. */
    bool insertLast(int value) {
              if(!isFull()) {
                
                LinkedNode* newnode =new LinkedNode(value),
                *temp = rear;

                if(isEmpty()) {
                    head = newnode;
                    rear = newnode;
                    
                }

                rear = newnode;
                // 必须判空,不然前插入后插入会使得循环链表断开
                if(temp) temp->next = rear;
                rear->next = head ;
                

                size++;
                return true;

        }
        
        return false;
    }
    
    /** Deletes an item from the front of Deque. Return true if the operation is successful. */
    bool deleteFront() {
             if(!isEmpty()) {
                 
                 if(rear == head) {
                    rear = nullptr;
                    head = nullptr;
                     size--;
                     return true;
                 }
                 
                 head = head -> next;
                 rear -> next = head;
                 size--;
                 return true;
                
        }
        return  false;
    }
    
    /** Deletes an item from the rear of Deque. Return true if the operation is successful. */
    bool deleteLast() {

           if(!isEmpty()) {
               
            LinkedNode* temp = head;
           // maintain_rear(rear);
               if(rear == head) {
                  rear = nullptr;
                  head = nullptr;
                   size--;
                   return true;
               }
               
           while(temp->next != rear) {
               temp = temp->next;
           }

            //kill
            temp ->next = head;
            rear = temp;

            size--;
            return true;

        }
        return  false;
        
    }
    
    /** Get the front item from the deque. */
    int getFront() {
        return isEmpty()?-1:head->val;
    }
    
    /** Get the last item from the deque. */
    int getRear() {
        return isEmpty()?-1:rear->val;
    }
    
    /** Checks whether the circular deque is empty or not. */
    bool isEmpty() {
        return  size == 0;
    }
    
    /** Checks whether the circular deque is full or not. */
    bool isFull() {
        return  size == capacity ;

    }

};
数组方法(只给出单向循环队列)
图解

入队出队

源码
class MyCircularQueue {

    /*
        This is the implementation based on array

    */
private:
    int size,head, rear;
    int * queue;
public:
    /** Initialize your data structure here. Set the size of the queue to be k. */
    
    MyCircularQueue(int k) :size(k+1),head(0),rear(0){
        // ***********detail***********
        queue = new  int[k+1];
    }
    
    /** Insert an element into the circular queue. Return true if the operation is successful. */
    bool enQueue(int value) {
        if(!isFull()){
            queue[rear]=value;
            rear = (rear+1) % size;
            return true;
        }
        return false;
    }
    
    /** Delete an element from the circular queue. Return true if the operation is successful. */
    bool deQueue() {
        if(!isEmpty()) {
            head  = (head + 1) % size;
            return true;
        }
        
        return false;
    }
    
    /** Get the front item from the queue. */
    int Front() {
        return isEmpty()?-1:queue[head];
    }
    
    /** Get the last item from the queue. */
    int Rear() {

        // ***********detail***********
        return isEmpty()?-1:queue[(rear-1+size)%size];
    }
    
    /** Checks whether the circular queue is empty or not. */
    bool isEmpty() {
        return rear == head;
    }
    
    /** Checks whether the circular queue is full or not. */
    bool isFull() {
        // ***********detail***********
        return (rear+1)%size==head;
    }
};
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值