算法基础 典型题(一)栈/队列/堆

记录算法基础题思路:

队列实现栈:核心在于出入顺序有差别,可以再入队之后,把队列里面的旧数据重新出队入队,就能和栈顺序一致;

栈实现队列:可以通过两个队列模拟,一个队列负责出数据,一个负责入数据,当需要出时,如果出队为空,把入队的数据送入出队;

包含min函数栈:1、新栈去记录每次最小值 2 使用变量min记录当前最小,如果入栈的变量更小就先把旧min入栈,然后刷新min,出栈的时候如果==min,就多pop一个值刷新min

合法出栈校验:利用空栈校验,连续入栈输入顺序,当和输出相等就pop,最后为空就说明合法;

简单计算器:一个栈记录符号,一个栈记录数值,当遇到)就开始 pop 符号栈和数据栈 开始计算直到 (,把结果入栈,到最后再计算一次 作为最终结果;

求第K大数:1、先排序再取值 2、构建一个size为k的小顶堆,如果遍历的发现堆size==k,只有当num > top时,再pop和push更新堆,堆顶为结果;

寻中位数:构造一个大顶堆(小的一半数) 和 小顶堆(大的一半数),每次先往数量少的一方加,如果加不进去,比如往大顶堆添加元素的时候,发现比小顶堆头大,就交换一下 把小顶头入大顶堆,然后原数入小顶堆;

step1:

队列实现栈:https://leetcode-cn.com/problems/implement-stack-using-queues/

使用队列实现栈的下列操作:
push(x) -- 元素 x 入栈
pop() -- 移除栈顶元素
top() -- 获取栈顶元素
empty() -- 返回栈是否为空

    /** Push element x onto stack. */
    void push(int x) {
        unsigned int size = que.size();
        que.push(x);
        while (size > 0) {
            que.push(que.front());
            que.pop();
            size--;
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    int pop() {
        int val = que.front();
        que.pop();
        return val;
    }
    
    /** Get the top element. */
    int top() {
        return que.front();
    }
    
    /** Returns whether the stack is empty. */
    bool empty() {
        return  que.empty();
    }

 

栈实现队列:https://leetcode-cn.com/problems/implement-queue-using-stacks/

使用栈实现队列的下列操作:
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。

   /** Push element x to the back of queue. */
    void push(int x) {
        pushStack.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
        if (popStack.empty() == true) {
            int size = pushStack.size();
            while (size > 0) {
                int val = pushStack.top();
                pushStack.pop();
                popStack.push(val);
                size--;
            }
        }

        if (popStack.empty() != true) {
            int val = popStack.top();
            popStack.pop(); 
            return val;          
        }

        return -1;
    }
    
    /** Get the front element. */
    int peek() {
        if (popStack.empty() == true) {
            int size = pushStack.size();
            while (size > 0) {
                int val = pushStack.top();
                pushStack.pop();
                popStack.push(val);
                size--;
            }
        }
        if (popStack.empty() != true) {
            int val = popStack.top();
            return val;          
        }
        return -1;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        if (pushStack.empty() == true && popStack.empty() == true) {
            return true;
        }
        return false;
    }

包含min函数栈:https://leetcode-cn.com/problems/min-stack/

设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。
push(x) —— 将元素 x 推入栈中。
pop() —— 删除栈顶的元素。
top() —— 获取栈顶元素。
getMin() —— 检索栈中的最小元素。

   void push(int x) {
        if (x <= min) {
            dataStack.push(min);
            min = x;
        }
        dataStack.push(x);
    }
    
    void pop() {
        int val = dataStack.top();
        dataStack.pop();
        if (val == min) {
            min = dataStack.top();
            dataStack.pop();
        }
    }
    
    int top() {
        return dataStack.top();
    }
    
    int getMin() {
        if (dataStack.empty() == true) {
            return -1;
        }
        return min;
    }

合法出栈校验:https://leetcode-cn.com/problems/validate-stack-sequences/

给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;否则,返回 false 。

    bool validateStackSequences(vector<int>& pushed, vector<int>& popped) {
        unsigned int pop_pos = 0;
        for (unsigned int i = 0; i < pushed.size(); i++) {
            dataStack.push(pushed[i]);
            while ((dataStack.empty() != true) && (dataStack.top() == popped[pop_pos])) {
                dataStack.pop();
                pop_pos++;
            }
        }
        return dataStack.empty() == true;
    }

简单计算器:https://leetcode-cn.com/problems/basic-calculator/

实现一个基本的计算器来计算一个简单的字符串表达式的值。
字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格  。
示例:
输入: "1 + 1"
输出: 2

    int calculate(string s) {
        stack<char> opr;
        stack<int> num;
        num.push(0);
        int idx = 0;
        while(idx < s.size()){
            if(s[idx] == ' ')
                ++idx;
            else if(s[idx] == '(' || s[idx] == '+' || s[idx] == '-'){
                opr.push(s[idx]);
                ++idx;
            }
            else if(s[idx] == ')'){
                int sum = 0;
                while(opr.top() != '('){
                    char op = opr.top();
                    opr.pop();
                    int n = num.top();
                    num.pop();
                    sum += op=='+'? n: -n;
                }
                sum += num.top();
                num.pop();
                num.push(sum);
                opr.pop();
                ++idx;
            }
            else{
                unsigned int val = 0;
                while (s[idx] >= '0' && s[idx] <= '9') {
                    val = val * 10 + s[idx] - '0';
                    idx++;
                }
                num.push(val);
            }
        }
        int sum = 0;
        while(!opr.empty()){
            char op = opr.top();
            opr.pop();
            int n = num.top();
            num.pop();
            sum += op=='+'? n: -n;
        }
        return sum + num.top();
    }

求第K大数:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 :
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5

    int findKthLargest(vector<int>& nums, int k) {
        priority_queue<int,vector<int>,greater<int>> small_heap;
        for(auto num:nums){
            if(small_heap.size() < k) {
                small_heap.push(num);            
            } else {
                if (num > small_heap.top()) {
                    small_heap.pop();
                    small_heap.push(num);
                }
            }
        }
        return small_heap.top();
    }

 

寻中位数:https://leetcode-cn.com/problems/find-median-from-data-stream/

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。

     /* 大顶堆 放小的一半,堆顶为最大值 */
    priority_queue<int, vector<int>, less<int>> low_heap;
     /* 小顶堆 放大的一半,堆顶为最小值 */
    priority_queue<int, vector<int>, greater<int>> high_heap;
public:
    // Adds a number into the data structure.
    void addNum(int num)
    {
        if (low_heap.empty() == true) {
            low_heap.push(num);
            return;
        }
        
        if (low_heap.size() == high_heap.size()) {
            /* 两堆数量一样多,按实际大小判断放哪一堆里面 */
            if (num > low_heap.top()) {
                high_heap.push(num);
            } else {
                low_heap.push(num);               
            }
        } else if (high_heap.size() > low_heap.size()) {
            /* 大的数比较多,优先放low堆,放不进去就把high的top换过来 */
            if (num <= high_heap.top()) {
                low_heap.push(num);
            } else {
                low_heap.push(high_heap.top());
                high_heap.pop();
                high_heap.push(num);
            }
        } else {
            /* 小的数比较多,优先放high堆,放不进去就把low的top换过来 */
            if (num >= low_heap.top()) {
                high_heap.push(num);
            } else {
                high_heap.push(low_heap.top());
                low_heap.pop();
                low_heap.push(num);
            }
        }
    }

    double findMedian()
    {
        if (low_heap.size() == high_heap.size()) {
            return (low_heap.top() + high_heap.top()) / 2.0;
        } else if (low_heap.size() > high_heap.size()) {
            return low_heap.top();
        } else {
            return high_heap.top();
        }
    }

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值