java栈和队列实例

0 基础代码

Stack<Integer> st = new Stack<>();          //创建栈
st.push();                              //入栈
st.pop();                                //取出栈顶元素并在栈中删除
st.peek();                        //返回栈顶元素
st.isEmpty();             //判断是否为空
st.size();              //统计栈内元素个数

Queue<Integer> qu = new LinkedList<>();        //构造队列
qu.offer();                  //入队
qu.poll();                //出队并删除
qu.peek();                 //返回队首元素
qu.isEmpty();
qu.size();

//字符串转数字
Integer.valueOf(str);   
Integer.parseInt(str);
//数字转字符串
nums.toString();          
String.valueOf(nums);

Map<String, String> map = new HashMap<String, String>();
map.put("key1", "value1");
map.get("key1");
map.remove("key1");
map.clear();
//遍历map
for(Map<String, String> map : map.entrySet()) {
      String key = entry.getKey();
      String value = entry.getValue();
}

1. 理论基础

栈:先进后出
队列:先进先出

2. 用栈实现队列:需要两个栈

class MyQueue {
    
    //需要两个栈来处理
    Stack<Integer>  stackIn;        
    Stack<Integer>  stackOut;

    public MyQueue() {
        stackIn = new Stack<>();
        stackOut = new Stack<>();
    }
    
    public void push(int x) {
        stackIn.push(x);                 //入栈和入队列是一样的
    }
    
    public int pop() {
        moveStackIn();
        return stackOut.pop();
    }
    
    public int peek() {
        moveStackIn();
        return stackOut.peek();
    }
    
    public boolean empty() {
        return stackIn.isEmpty() && stackOut.isEmpty();   //只有两个都为空的时候队列才是空的
    }
    
    //将栈StackIn的元素放入到StackOut中
    private void moveStackIn() {
        if (!stackOut.isEmpty()) return;
        while (!stackIn.isEmpty()) {
            stackOut.push(stackIn.pop());
        }
    }
}

3. 用队列实现栈:使用一个queue实现

class MyStack {
    //一个队列实现
    Queue<Integer> myQueue;
    public MyStack() {
        myQueue = new LinkedList<>();
    }
    
    public void push(int x) {
        myQueue.offer(x);                         //在入队的时候就处理,将最后一个之前的统统掉头
        int size = myQueue.size();
        while (size > 1) {
            myQueue.offer(myQueue.poll());        //将最后一个之前的取出来又从队列入口放进去
            size --;
        }
        
    }
    
    public int pop() {
        return myQueue.poll();
    }
    
    public int top() {
        return myQueue.peek();
    }
    
    public boolean empty() {
        return myQueue.isEmpty();
    }
}
//用两个队列来做
class MyStack {
    Queue<Integer> queue1;             //它的数据顺序和栈的一样
    Queue<Integer> queue2;             //辅助队列,作缓存数据

    public MyStack() {
        queue1 = new LinkedList<>();
        queue2 = new LinkedList<>();
    }
    
    public void push(int x) {
        queue2.offer(x);
        while (!queue1.isEmpty()) {
            queue2.offer(queue1.poll());
        }
        
        Queue<Integer> queueTemp = queue1;
        queue1 = queue2;
        queue2 =queueTemp;
    }
    
    public int pop() {
        return queue1.poll();
    }
    
    public int top() {
        return queue1.peek();
    }
    
    public boolean empty() {
        return queue1.isEmpty();
    }
}

4 括号匹配

class Solution {
    public boolean isValid(String s) {
        if(s.length() % 2 != 0) return false;   //长度为奇数,肯定不符合
        Stack<Character> stack = new Stack<>();
        for(int i = 0; i < s.length(); i++) {
            int ch = s.charAt(i);
            if(ch == '(') stack.push(')');
            else if(ch == '[') stack.push(']');
            else if(ch == '{') stack.push('}');
            else if(stack.isEmpty() || stack.peek() != ch) return false;
            else{
                stack.pop();
            }
        }
        return stack.isEmpty();
    }
}

5. 删除字符串中所有相邻重复项

class Solution {
    public String removeDuplicates(String s) {
        if(s.length() == 1) {
            return s;
        }
        int len = s.length();
       Stack<Character> stack = new Stack<>();
       stack.push(s.charAt(len - 1));
       //从后遍历到时候直接把栈的元素一个个pop()出来就行了
       for(int i = len - 2; i >= 0; i--) {    
           if(!stack.isEmpty()) {
               if( s.charAt(i) != stack.peek()) {
                    stack.push(s.charAt(i));
                    }
                else {
                    stack.pop();
                }
           }else{
               stack.push(s.charAt(i));  //如果栈空了就将当前元素入栈
           }    
       }
       StringBuilder sb = new StringBuilder();
       while(!stack.isEmpty()) {
           sb.append(stack.pop());
       }
       return sb.toString();
    }
}

6. 求值逆波兰表达式

class Solution {
    public int evalRPN(String[] tokens) {
        Stack<Integer> stack = new Stack<>();
        for(int i = 0; i < tokens.length; i++) {
            if("+".equals(tokens[i])) {
                stack.push(stack.pop() + stack.pop());
            }else if("-".equals(tokens[i])){
                stack.push(-stack.pop() + stack.pop());
            }else if("*".equals(tokens[i])) {
                stack.push(stack.pop() * stack.pop());
            }else if("/".equals(tokens[i])) {
                int temp1 = stack.pop();
                int temp2 = stack.pop();
                stack.push(temp2 / temp1);
            }else {
                stack.push(Integer.valueOf(tokens[i]));     //转成整数
            }
        }
        return stack.pop();
    }
}

7. 滑动窗口最大值:双端队列deque

【关键在于将队列里面的元素按递减排列】

//队列求解
class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        MyDeque deque = new MyDeque();
        int len = nums.length;
        int[] res = new int[len - k + 1];
        int num = 0;
        //先将前k个入队列
        for(int i = 0; i < k; i++) {
            deque.add(nums[i]);
        }
        res[num++] = deque.peek();
        for(int i = k; i < nums.length; i++) {
            deque.poll(nums[i - k]);           //保持滑动窗口大小不变
            deque.add(nums[i]);                //当前元素加入队列
            res[num++] = deque.peek();         //因为是单调递减的,所以直接取队首元素就好
        }
        return res;

    }
}

class MyDeque {
    Deque<Integer> deque = new LinkedList<>();

    public void poll(int val) {
        if(!deque.isEmpty() && val == deque.peek()) {
            deque.poll();
        }
    }

    public void add(int val) {
        //如果当前元素大于队列最后一个,就将对列后面的都弹出
        //保证队列是按照递减方式排列的
        while(!deque.isEmpty() && val > deque.getLast()) {
            deque.removeLast();
        }
        deque.add(val);
    }

    public int peek() {
       return deque.peek();
    }
}

8. 前k个高频元素

基于小顶堆实现,小顶堆是基于树结构实现的,它的根节点最小,大顶堆则是根节点最大。因此找前k个最小就是大顶堆,找k个最大就是小顶堆。

class Solution {
    public int[] topKFrequent(int[] nums, int k) {
        if(nums.length == 1) {
            return nums;
        }
        int len = nums.length;
        HashMap<Integer, Integer> map = new HashMap<>();
        Arrays.sort(nums);
        //统计频次,因为map里面key值能重复,所以以频次作为value值
        for(int num : nums) {
            map.put(num, map.getOrDefault(num, 0) + 1);
        }
        //System.out.println(map);
        /*int freq = 1;
        for(int i = 1; i < len; i++) {
            if(nums[i] == nums[i - 1]) {
                freq ++;
            }
            else{
                map.put(nums[i - 1], freq);
                freq = 1;
            }
        }
        map.put( nums[len - 1], freq);
        */
        //基于小顶堆实现
        //小顶堆是基于树结构实现的,它的根节点最小
        Queue<int[]> queue = new PriorityQueue<>((p1,p2) -> p1[1] - p2[1]);
        for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
            if(queue.size() < k) {
                queue.offer(new int[]{entry.getKey(), entry.getValue()});    //将键值对放入key中
            }
            else{
                if(entry.getValue() > queue.peek()[1]) {
                    queue.poll();
                    queue.offer(new int[]{entry.getKey(), entry.getValue()});
                }
            } 
        }
        //堆维护好了之后寻找堆里面剩余的k个最大元素
         int[] res = new int[k];
         for(int i = k - 1; i >= 0; i--) {
             res[i] = queue.poll()[0];         //先弹出的是小的,后弹出的是大的,弹出的是key,也就是我们的nums[i]
         }
        return res;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值