堆/栈/队列

用两个栈实现队列

描述
用两个栈来实现一个队列,使用n个元素来完成 n 次在队列尾部插入整数(push)和n次在队列头部删除整数(pop)的功能。 队列中的元素为int类型。保证操作合法,即保证pop操作时队列内已有元素。

解题思路:

借助栈的先进后出规则模拟实现队列的先进先出
1、当插入时,直接插入 stack1
2、当弹出时,当 stack2 不为空,弹出 stack2 栈顶元素,如果 stack2 为空,将 stack1 中的全部数逐个出栈入栈 stack2,再弹出 stack2 栈顶元素

代码展示:

public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();

public void push(int node) {
stack1.push(node);
}

public int pop() {
if (stack2.size() <= 0){
while (stack1.size() != 0){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}

包含min函数的栈

描述

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的 min 函数,输入操作时保证 poptopmin 函数操作时,栈中一定有元素。

此栈包含的方法有:
push(value):将value压入栈中
pop():弹出栈顶元素
top():获取栈顶元素
min():获取栈中最小元素

数据范围:操作数量满足 0 \le n \le 300 \0n300 ,输入的元素满足 |val| \le 10000 \val10000
进阶:栈的各个操作的时间复杂度是 O(1)\O(1) ,空间复杂度是 O(n)\O(n)

方法:双栈法(推荐使用)

知识点:栈

栈是一种仅支持在表尾进行插入和删除操作的线性表,这一端被称为栈顶,另一端被称为栈底。元素入栈指的是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;元素出栈指的是从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。

思路:

我们都知道栈结构的push、pop、top操作都是O(1)O(1)O(1),但是min函数做不到,于是想到在push的时候就将最小值记录下来,由于栈先进后出的特殊性,我们可以构造一个单调栈,保证栈内元素都是递增的,栈顶元素就是当前最小的元素。

具体做法:

  • step 1:使用一个栈记录进入栈的元素,正常进行push、pop、top操作。
  • step 2:使用另一个栈记录每次push进入的最小值。
  • step 3:每次push元素的时候与第二个栈的栈顶元素比较,若是较小,则进入第二个栈,若是较大,则第二个栈的栈顶元素再次入栈,因为即便加了一个元素,它依然是最小值。于是,每次访问最小值即访问第二个栈的栈顶。
Java实现代码:
public class Solution {
    Stack<Integer> s1 = new Stack<Integer>();
    //用于存储最小min
    Stack<Integer> s2 = new Stack<Integer>();
    
    public void push(int node) {
         s1.push(node); 
        //空或者新元素较小,则入栈
        if(s2.isEmpty() || s2.peek() > node) 
            s2.push(node);
        else
            //重复加入栈顶
            s2.push(s2.peek()); 
    }
    
    public void pop() {
        s1.pop();
        s2.pop();
    }
    
    public int top() {
        return s1.peek();
    }
    
    public int min() {
         return s2.peek();
    }
}

有效括号序列

描述

给出一个仅包含字符'(',')','{','}','['和']',的字符串,判断给出的字符串是否是合法的括号序列
括号必须以正确的顺序关闭,"()"和"()[]{}"都是合法的括号序列,但"(]""([)]"不合法
数据范围:字符串长度 0\le n \le 100000n10000

要求:空间复杂度 O(n)O(n),时间复杂度 O(n)O(n)

算法思想二:栈

解题思路:

建立一个栈,存储遍历的字符串再进行对比
1、遍历字符串遇到 ‘(’ '[' '{' 左括号,就把相应的右括号(‘)’ ']' '}')入栈
2、如果遍历遇到右括号 ‘)’ ']' '}' ,则判断是否和栈顶元素相同
1、不同则直接返回false
2、相同则将栈顶元素出栈
3、遍历结束判断栈是否为空
代码如下:
public class Solution {
    /**
     * 
     * @param s string字符串 
     * @return bool布尔型
     */
    public boolean isValid (String s) {
        // write code here 
        Stack<Character>stack = new Stack<Character>();
         for(char c: s.toCharArray()){
            // 碰到左括号,就把相应的右括号入栈
            if(c=='(')stack.push(')');
            else if(c=='[')stack.push(']');
            else if(c=='{')stack.push('}');
            // 如果是右括号判断是否和栈顶元素匹配
            else if(stack.isEmpty()||c!=stack.pop())return false;
    }
         return stack.isEmpty();
    }
}

最小的K个数

描述

给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
数据范围:0\le k,n \le 100000k,n10000,数组中每个数的大小0 \le val \le 10000val1000
要求:空间复杂度 O(n)O(n) ,时间复杂度 O(nlogn)O(nlogn)
方法一:堆排序(推荐使用)

知识点:优先队列

优先队列即PriorityQueue,是一种内置的机遇堆排序的容器,分为大顶堆与小顶堆,大顶堆的堆顶为最大元素,其余更小的元素在堆下方,小顶堆与其刚好相反。且因为容器内部的次序基于堆排序,因此每次插入元素时间复杂度都是O(log2n)O(log_2n)O(log2n),而每次取出堆顶元素都是直接取出。

思路:

要找到最小的k个元素,只需要准备k个数字,之后每次遇到一个数字能够快速的与这k个数字中最大的值比较,每次将最大的值替换掉,那么最后剩余的就是k个最小的数字了。

如何快速比较k个数字的最大值,并每次替换成较小的新数字呢?我们可以考虑使用优先队列(大根堆),只要限制堆的大小为k,那么堆顶就是k个数字的中最大值,如果需要替换,将这个最大值拿出,加入新的元素就好了。

具体做法:

  • step 1:利用input数组中前k个元素,构建一个大小为k的大顶堆,堆顶为这k个元素的最大值。
  • step 2:对于后续的元素,依次比较其与堆顶的大小,若是比堆顶小,则堆顶弹出,再将新数加入堆中,直至数组结束,保证堆中的k个最小。
  • step 3:最后将堆顶依次弹出即是最小的k个数。
代码如下:
public class Solution {
    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        //排除特殊情况
        if(k == 0 || input.length == 0)
            return res;
        //大根堆
        PriorityQueue<Integer> q = new PriorityQueue<>((o1, o2)->o2.compareTo(o1));
        //构建一个k个大小的堆 
        for(int i = 0; i < k; i++)
            q.offer(input[i]);
        for(int i = k; i < input.length; i++){
            //较小元素入堆
            if(q.peek() > input[i]){ 
                q.poll();
                q.offer(input[i]);
            }
        }
        //堆中元素取出入数组
        for(int i = 0; i < k; i++)
            res.add(q.poll());
        return res;
        
    }
    
}








#Java#
全部评论
典型的笔试题啊
点赞 回复 分享
发布于 2022-08-25 18:41 陕西

相关推荐

10-30 10:16
南京大学 Java
永远的鹅孝子:给南大✌️跪了
点赞 评论 收藏
分享
评论
1
4
分享
牛客网
牛客企业服务