数据结构与算法– 栈(Stack)

数据结构与算法– 栈(Stack)

1、栈定义

栈是限定仅在表尾进行插入和删除操作的线性表。

  • 后进先出(Last in, First out)
  • push 入栈,pop 出栈,top栈顶

2、栈的数据类型

ADT 栈
Data
	同线性表 元素具有相同类型,相邻元素具有前驱后继关系
Operation
	InitStack(*S);	// 初始化操作 建立空栈S
	DestroyStack(*S) //若栈存在则销毁
	ClearStack(*S) //将栈清空
	StackEmpty(S);	// 若栈为空,返回true,否则返回false
	GetTop(S,*e) //若栈存在且为空,用e返回S的栈顶元素
	Push(*S,e) //若栈S存在,插入新元素e到栈S的栈顶元素中
	Pop(*S,*e) //删除栈中栈顶元素,并用e返回其值
	StackLength(S) // 返回栈S中元素个数
endADT

3、结构定义

typedef int SElemType;
// 建栈
typedef struct  {
	SElemType data[MAXSIZE];
	
	int *top;	// 栈顶指针
}sqStack;

4、算法题解

232. Implement Queue using Stacks (Easy) --用栈实现队列

栈的顺序为后进先出,而队列的顺序为先进先出。使用两个栈实现队列,一个元素需要经过两个栈才能出队列,在经过第一个栈时元素顺序被反转,经过第二个栈时再次被反转,此时就是先进先出顺序。

思路

将一个栈当作输入栈,用于压入 push传入的数据;另一个栈当作输出栈,用于pop 和peek 操作。

每次pop 或peek 时,若输出栈为空则将输入栈的全部数据依次弹出并压入输出栈,这样输出栈从栈顶往栈底的顺序就是队列从队首往队尾的顺序。


class MyQueue {

    private Stack<Integer> in = new Stack<>();
    private Stack<Integer> out = new Stack<>();

    public void push(int x) {
        in.push(x);
    }

    public int pop() {
        in2out();
        return out.pop();
    }

    public int peek() {
        in2out();
        return out.peek();
    }

    private void in2out() {
        if (out.isEmpty()) {
            while (!in.isEmpty()) {
                out.push(in.pop());
            }
        }
    }

    public boolean empty() {
        return in.isEmpty() && out.isEmpty();
    }
}

225. Implement Stack using Queues (Easy) --用队列实现栈

在将一个元素 x 插入队列时,为了维护原来的后进先出顺序,需要让 x 插入队列首部。而队列的默认插入顺序是队列尾部,因此在将 x 插入队列尾部之后,需要让除了 x 之外的所有元素出队列,再入队列。

class MyStack {

    private Queue<Integer> queue;

    public MyStack() {
        queue = new LinkedList<>();
    }

    public void push(int x) {
        queue.add(x);
        int cnt = queue.size();
        while (cnt-- > 1) {
            queue.add(queue.poll());
        }
    }

    public int pop() {
        return queue.remove();
    }

    public int top() {
        return queue.peek();
    }

    public boolean empty() {
        return queue.isEmpty();
    }
}

155. Min Stack (Easy) --最小值栈

思路

我们通过两个栈来实现,栈A用来执行正常的操作,栈B用来保存栈A当前的最小元素,
出栈时,需要进行对比,若栈 A 和栈 B 栈顶元素相同,则同时出栈,此时 B 的栈顶保存的仍为此时栈 A 的最小元素。

class MinStack {
public:
    stack<int> data;
    stack<int> minstack;
   
    MinStack() {

    }
    
    void push(int val) {
        data.push(val);
        if(minstack.empty() || val <= minstack.top()){
            minstack.push(val);
        }

    }
    
    void pop() {
        if(data.top() == minstack.top()){
            minstack.pop();
        }
        data.pop();
    }
    
    int top() {
        return data.top();
    }
    
    int getMin() {
        return minstack.top();
    }
};

1310. 子数组异或查询

在这里插入图片描述

思路

如果数组 arr 的长度为 nn,数组queries 的长度为m (即有 m个查询),则最坏情况下每个查询都需要 O(n)O(n) 的时间计算结果,总时间复杂度是 O(nm),会超出时间限制,因此必须优化。
由于有 m个查询,对于每个查询都要计算结果,因此应该优化每个查询的计算时间。理想情况下,每个查询的计算时间应该为 O(1)。为了将每个查询的计算时间从 O(n) 优化到 O(1),需要计算数组的前缀异或。
在这里插入图片描述
在这里插入图片描述

class Solution {
public:
    vector<int> xorQueries(vector<int>& arr, vector<vector<int>>& queries) {
        int n = arr.size();
        vector<int> xors(n + 1);
        for (int i = 0; i < n; i++) {
            xors[i + 1] = xors[i] ^ arr[i];
        }
        int m = queries.size();
        vector<int> ans(m);
        for (int i = 0; i < m; i++) {
            ans[i] = xors[queries[i][0]] ^ xors[queries[i][1] + 1];
        }
        return ans;
    }
};

PYTHON3:

  • 时间复杂度:令 arr 数组长度为 n,qs 数组的长度为 m。创建树状数组复杂度为 O(nlogn);
  • 查询的复杂度为 O(mlogn)。整体复杂度为 O((n+m)logn)
  • 空间复杂度:O(n)O(n)
class Solution:
    def xorQueries(self, arr: List[int], queries: List[List[int]]) -> List[int]:
        prexor = list(accumulate([0] + arr, xor))
        return [prexor[i] ^ prexor[j + 1] for i, j in queries]

20. Valid Parentheses (Easy) -用栈实现括号匹配
在这里插入图片描述

class Solution {
public:
    bool isValid(string s) {
        if (s.length()%2 == 1)
        {
            return false;
        }
        stack<char> st; 
        for (char& c:s)
        {
            if (c == '(' || c == '[' || c == '{')
            {
                st.push(c);
                continue;
            }
            if (c == ')' || c == ']' || c == '}')
            {
                if (st.empty())
                {
                    return false;
                }
                else  
                {           
                    if( (c ==')' && st.top() == '(' ) || ( c == ']' && st.top() == '[' ) || ( c == '}' && st.top()== '{' ) )
                    {
                        st.pop();
                    }
                    else return false;
                }
            }
        }
      return st.empty();
    }
};

739. Daily Temperatures (Medium)–数组中元素与下一个比它大的元素之间的距离

Input: [73, 74, 75, 71, 69, 72, 76, 73]
Output: [1, 1, 4, 2, 1, 1, 0, 0]
class Solution {
public:
    vector<int> dailyTemperatures(vector<int>& temperatures) {
        vector<int> dp(temperatures.size(),0);
        deque<int> q;
        for(int i = 0 ; i < temperatures.size(); i++){
            if(q.empty()){
                q.push_back(i);
                continue;
            }
            while(!q.empty()&&temperatures[i] > temperatures[q.back()]){
                dp[q.back()] = i-q.back();
                q.pop_back();

            }
            q.push_back(i);
        }
            return dp;
    }
};

503. Next Greater Element II (Medium)–循环数组中比当前元素大的下一个元素

Input: [1,2,1]
Output: [2,-1,2]
Explanation: The first 1's next greater number is 2;
The number 2 can't find next greater number;
The second 1's next greater number needs to search circularly, which is also 2.

class Solution {
public:
    vector<int> nextGreaterElements(vector<int>& nums) {
        int n = nums.size();
        vector<int> ret(n, -1);
        stack<int> stk;
        for (int i = 0; i < n * 2 - 1; i++) {
            while (!stk.empty() && nums[stk.top()] < nums[i % n]) {
                ret[stk.top()] = nums[i % n];
                stk.pop();
            }
            stk.push(i % n);
        }
        return ret;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值