LeetCode题目练习-栈&队列

有效括号

Given a string containing just the characters ‘(’, ‘)’, ‘{’, ‘}’, ‘[’
and ‘]’, determine if the input string is valid.

An input string is valid if:

Open brackets must be closed by the same type of brackets. Open
brackets must be closed in the correct order. Note that an empty
string is also considered valid.

Example 1:

Input: “()” Output: true

// 执行用时 :0 ms, 在所有 C++ 提交中击败了100.00%的用户
// 内存消耗 :8.4 MB, 在所有 C++ 提交中击败了86.49%的用户
class Solution {
public:
    bool isValid(string s) {
        if(!s.length()) return 1;
        stack<char> st;
        for(char &i : s){//重点
            switch (i){
                case '(':
                case '{':
                case '[':
                    st.push(i);
                    break;
                case ')':
                    if(!st.size()||st.top() != '(') return 0;
                    st.pop();
                    break;
                case ']':
                    if(!st.size()||st.top() != '[') return 0;
                    st.pop();
                    break;
                case '}':
                    if(!st.size()||st.top() != '{') return 0;
                    st.pop();   
            }//代码还能优化吗
        }
        if(!st.size()) return 1;
        return 0;
    }
};
#python解法 时间复杂度O(n2)
class Solution:
    def isValid(self, s):
        while '{}' in s or '()' in s or '[]' in s:
            s = s.replace('{}', '')
            s = s.replace('[]', '')
            s = s.replace('()', '')
        return s == ''

栈实现队列

class MyQueue {
public:
    /** Initialize your data structure here. */
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        s1.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if(!s2.size()){
            while(s1.size()){
                s2.push(s1.top());
                s1.pop();////弹出栈顶元素, 但不返回其值
            }
        }
        int val = s2.top();
        s2.pop();
        return val;
    }
    
    /** Get the front element. */
    int peek() {
        if(!s2.size()){
            while(s1.size()){
                s2.push(s1.top());
                s1.pop();
            }
        }
        return s2.top();
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return !(s1.size()+s2.size());
    }
private:
        stack<int> s1,s2;
};

/**
 * 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();
 */

队列实现栈

class MyStack {
public:
    /** Initialize your data structure here. */
    MyStack() {
        
    }
    
    /** Push element x onto stack. */
    void push(int x) {
        q1.push(x);
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        while(q1.size() != 1){
            q2.push(q1.front());
            q1.pop();
        }
        int num = q1.front();
        q1.pop();
        while(q2.size()){
            q1.push(q2.front());
            q2.pop();
        }
        return num;
    }
    
    /** Get the top element. */
    int top() {
        return q1.back();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return !(q1.size()+q2.size());
    }
private:
    queue<int> q1,q2;
};

/**
 * 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();
 */

返回数据流中第k大的元素(小顶堆)

在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出 (first in, largest out)的行为特征。通常采用堆或二叉搜索树来实现。

Design a class to find the kth largest element in a stream. Note that
it is the kth largest element in the sorted order, not the kth
distinct element.

Your KthLargest class will have a constructor which accepts an integer
k and an integer array nums, which contains initial elements from the
stream. For each call to the method KthLargest.add, return the element
representing the kth largest element in the stream.

Example:

int k = 3; int[] arr = [4,5,8,2]; KthLargest kthLargest = new
KthLargest(3, arr); kthLargest.add(3); // returns 4
kthLargest.add(5); // returns 5 kthLargest.add(10); // returns 5
kthLargest.add(9); // returns 8 kthLargest.add(4); // returns 8

  • 算法一:维护一个自动排序的数组,保存整个数组中k个较大值:插入新数并自动排序后,若有k个以上的元素,则去除最小的那个即开头元素。时间复杂度N*klog(k) (插入N个数据,每次都排序)
class KthLargest {
public:
    //维护一个新数组st,是数组nums中的k个较大值
    KthLargest(int k, vector<int>& nums) {
        for(int i : nums){
            st.insert(i);
            if(st.size() > k){
                //如果st有k+1个元素,那么去除最小的元素,也就是开头那个
                st.erase(st.begin());
            }
        }
        K = k;//需要把k保存起来
    }
    int add(int val) {
        st.insert(val);
        //如果元素超过k个,去除最小的那个
        if(st.size() > K){
            st.erase(st.begin());
        }
        return *st.begin();
    }
private:
    int K;
    multiset<int> st;//自动排序 允许重复
};

/**
 * Your KthLargest object will be instantiated and called as such:
 * KthLargest* obj = new KthLargest(k, nums);
 * int param_1 = obj->add(val);
 */
  • 算法二:维护一个大小为k的小顶堆。每次插入数据时,如果比堆顶元素小,则不用插入;如果大,则插入并调整堆。输出堆底最后一个元素即为第k个最大元素。时间复杂度:最好N*1,最坏N*log(2k)=N*logk(取后者)。
class KthLargest {
    int K;
    priority_queue<int, vector<int>, greater<int>> pq;
/*
priority_queue<Type, Container, Functional>
Type为数据类型, Container为保存数据的容器,Functional为元素比较方式。
如果不写后两个参数,那么容器默认用的是vector,比较方式默认用operator<,
也就是优先队列是大顶堆,队头元素最大,本题为小顶堆。
*/
public:
    KthLargest(int k, vector<int>& nums) {
        for (int n : nums) {
            pq.push(n);
            if (pq.size() > k) pq.pop();
        }       
        K = k;
    }
    
    int add(int val) {
        pq.push(val);
        if (pq.size() > K) pq.pop();
        return pq.top();
    }
};
/*作者:guohaoding
链接:https://leetcode-cn.com/problems/kth-largest-element-in-a-stream/solution/703-shu-ju-liu-zhong-de-di-kda-yuan-su-liang-chong/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/

滑动窗口最大值(优先队列)

Given an array nums, there is a sliding window of size k which is
moving from the very left of the array to the very right. You can only
see the k numbers in the window. Each time the sliding window moves
right by one position. Return the max sliding window.

Example:

Input: nums = [1,3,-1,-3,5,3,6,7], and k = 3 Output: [3,3,5,5,6,7]
Explanation:

Window position Max
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
  • 算法一:multiset保存当前的窗口,每次将当前窗口最大值传入answer数组中。pos指针从nums数组第一个元素指向最后一个元素,每次移动过程中向集合中插入所指元素。以k=3为例,pos = 3,4…时,窗口内元素个数大于3个,需要删除最左边的数据;pos=2,3,4…时,窗口元素个数大于等于3个,可以向ans数组写入当前窗口最大值。时间复杂度n*klog(k)
    注意C++中,end()不是指向最后一个元素,而是最后一个元素的后一个元素,所以返回最后一个元素时不能用*st.end()而要用*st.rbegin()
// 执行用时 :92 ms, 在所有 C++ 提交中击败了37.34%的用户
class Solution {
multiset<int> st;
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;     
        for(int pos = 0;pos < nums.size();pos++){
            if(pos >= k) st.erase(st.find(nums[pos-k]));//删除左边数据
            st.insert(nums[pos]);
            if(pos >= k-1) ans.push_back(*st.rbegin());
        }  
        return ans;
    }
};
  • 算法二:优先队列(大顶堆)
    思想同算法一,维护一个多重集合变为维护一个大顶堆,但是我不会C++优先队列中删除某特定值的元素,即删除窗口最左边的数据,挖坑。时间复杂度n*logk
  • 算法三:双端队列
    进新元素时,干掉比自己小的元素,时间复杂度n
class Solution {
vector<int> ans;
deque<int> dequ;
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        for (int pos = 0; pos < nums.size(); pos++) {
            if (!dequ.empty() && dequ.front() == pos-k) {
            	dequ.pop_front(); 
            } 
            while (!dequ.empty() && nums[pos] > nums[dequ.back()]){
			    dequ.pop_back();
			}
            dequ.push_back(pos);
            if (pos >= k-1) ans.push_back(nums[dequ.front()]);
        }
        return ans;
    }
};
发布了24 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Protocols7/article/details/103840612