栈和队列

用栈实现队列

leetcode232

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

class MyQueue {
    
    private Stack<Integer> in;
    private Stack<Integer> out;

    /** Initialize your data structure here. */
    public MyQueue() {
        in = new Stack<>();
        out = new Stack<>();
    }
    
    /** Push element x to the back of queue. */
    public void push(int x) {
        in.push(x);
    }
    
    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        inToOut();
        return out.pop();
    }
    
    /** Get the front element. */
    public int peek() {
        inToOut();
        return out.peek();
    }
    
    public void inToOut(){
        if(out.isEmpty()){
            while(!in.isEmpty()){
                out.push(in.pop());
            }
        }
    }
    /** Returns whether the queue is empty. */
    public boolean empty() {
        return in.isEmpty() && out.isEmpty();
    }
}

用队列实现栈

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

class MyStack {

    Queue<Integer> queue;
    /** Initialize your data structure here. */
    public MyStack() {
        queue = new LinkedList<>();
    }
    
    /** Push element x onto stack. */
    public void push(int x) {
        queue.add(x);
        int size = queue.size();
        while(size-- > 1){
            queue.add(queue.remove());
        }
    }
    
    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return queue.poll();
    }
    
    /** Get the top element. */
    public int top() {
        return queue.peek();
    }
    
    /** Returns whether the stack is empty. */
    public boolean empty() {
        return queue.size() == 0;
    }
}
class MyStack:

    def __init__(self):
        """
        Initialize your data structure here.
        """
        self.queue = []

    def push(self, x: int) -> None:
        """
        Push element x onto stack.
        """
        self.queue.append(x)
        for i in range(len(self.queue)):
            self.queue.append(self.queue.pop(0))

    def pop(self) -> int:
        """
        Removes the element on top of the stack and returns that element.
        """
        return self.queue.pop()

    def top(self) -> int:
        """
        Get the top element.
        """
        return self.queue[-1]

    def empty(self) -> bool:
        """
        Returns whether the stack is empty.
        """
        return not self.queue

最小值栈

leetcode155
设计一个支持 push ,pop ,top 操作,并能在常数时间内检索到最小元素的栈。

  • push(x) —— 将元素 x 推入栈中。
  • pop() —— 删除栈顶的元素。
  • top() —— 获取栈顶元素。
  • getMin() —— 检索栈中的最小元素。

法一:直接底层构造MinStack

class MinStack {
    private Node head;

    private class Node{
        int val;
        int min;
        Node next;

        public Node(int val, int min) {
            this.val = val;
            this.min = min;
            next = null;
        }
    }
    
    public void push(int x) {
        if (head == null) {
            head = new Node(x, x);
        }else {
            Node node = new Node(x, Math.min(x, head.min));
            node.next = head;
            head = node;
        }
    }
    
    public void pop() {
        head = head.next;
    }
    
    public int top() {
        return head.val;
    }
    
    public int getMin() {
        return head.min;
    }
}

法二:双栈实现,一个存储值,一个存储最小值

class MinStack {

    private Stack<Integer> dataStack;
    private Stack<Integer> minStack;
    private int min;

    public MinStack(){
        dataStack = new Stack<>();
        minStack = new Stack<>();
        min = Integer.MAX_VALUE;
    }
    public void push(int x) {
        dataStack.push(x);
        min = Math.min(x, min);
        minStack.push(min);
    }
    
    public void pop() {
        dataStack.pop();
        minStack.pop();
        min = minStack.isEmpty() ? Integer.MAX_VALUE : minStack.peek();
    }
    
    public int top() {
        return dataStack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

法三:用一个栈,但更新最小值时把原最小值再入栈一次

class MinStack {
    int min = Integer.MAX_VALUE;
    Stack<Integer> stack = new Stack<Integer>();
    public void push(int x) {
        //当前值更小
        if(x <= min){   
            //将之前的最小值保存
            stack.push(min);
            //更新最小值
            min=x;
        }
        stack.push(x);
    }

    public void pop() {
        //如果弹出的值是最小值,那么将下一个元素更新为最小值
        //这里进入if判断语句,已经先执行一次pop()
        if(stack.pop() == min) {
            min=stack.pop();
        }
    }

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

    public int getMin() {
        return min;
    }
}

法四:压入差值
同样是用一个 min 变量保存最小值。只不过栈里边我们不去保存原来的值,而是去存储入栈的值和最小值的差值。然后得到之前的最小值的话,我们就可以通过 min 值和栈顶元素得到,举个例子。

入栈 3,存入 3 - 3 = 0
|   |   min = 3
|   |     
|_0_|    
stack   

入栈 5,存入 5 - 3 = 2
|   |   min = 3
| 2 |     
|_0_|    
stack  

入栈 2,因为出现了更小的数,所以我们会存入一个负数,这里很关键
也就是存入  2 - 3 = -1, 并且更新 min = 2 
对于之前的 min 值 3, 我们只需要用更新后的 min - 栈顶元素 (-1) 就可以得到    
| -1|   min = 2
| 5 |     
|_3_|    
stack  

入栈 6,存入  6 - 2 = 4
| 4 |   min = 2
| -1| 
| 5 |     
|_3_|    
stack  

出栈,返回的值就是栈顶元素 4 加上 min,就是 6
|   |   min = 2
| -1| 
| 5 |     
|_3_|    
stack  

出栈,此时栈顶元素是负数,说明之前对 min 值进行了更新。
入栈元素 - min = 栈顶元素,入栈元素其实就是当前的 min 值 2
所以更新前的 min 就等于入栈元素 2 - 栈顶元素(-1) = 3
|   | min = 3
| 5 |     
|_3_|    
stack     
public class MinStack {
    long min;
	Stack<Long> stack;

	public MinStack(){
        stack=new Stack<>();
    }

	public void push(int x) {
		if (stack.isEmpty()) {
			min = x;
			stack.push(x - min);
		} else {
			stack.push(x - min);
			if (x < min){
				min = x; // 更新最小值
			}
				
		}
	}

	public void pop() {
		if (stack.isEmpty())
			return;
        //由于我们保存的是差值,所以可能造成溢出,所以我们用了数据范围更大的 long 类型。
		long pop = stack.pop();
		
		//弹出的是负值,要更新 min
		if (pop < 0) {
			min = min - pop;
		}

	}
	//???个人认为只要返回栈顶元素即可,min更新会在pop时,但提交错误
	public int top() {
		long top = stack.peek();
		//负数的话,出栈的值保存在 min 中
		if (top < 0) {
			return (int) (min);
        //出栈元素加上最小值即可
		} else {
			return (int) (top + min);
		}
	}

	public int getMin() {
		return (int) min;
	}
}

用栈实现括号匹配

leetcode20

示例 1:

输入: "()"
输出: true

示例 2:

输入: "()[]{}"
输出: true

示例 3:

输入: "(]"
输出: false

示例 4:

输入: "([)]"
输出: false

示例 5:

输入: "{[]}"
输出: true
  • 法一
class Solution {
    public boolean isValid(String s) {
    //字符长度必须是偶数,空字符串也为true
    if ((s.length() & 1)== 1){
            return false;
        }
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if (c == '(' || c == '{' || c == '['){
                stack.push(c);
            }else {
            //栈空,说明表达式无效,没有与此时右括号匹配的左括号
                if (stack.isEmpty()){
                    return false;
                }
                if (c == ')' && stack.peek() == '('){
                    stack.pop();
                }
                else if (c == '}' && stack.peek() == '{'){
                    stack.pop();
                }
                else if (c == ']' && stack.peek() == '['){
                    stack.pop();
                }else {
                	return false;
                }
            }
        }
        //栈不为空,false
        return stack.isEmpty();
    }
}
  • 法二:官方解法,用hashmap
class Solution {
    private Map<Character,Character> map;
    public Solution(){
        map = new HashMap<>();
        this.map.put(')','(');        
        this.map.put(']','[');
        this.map.put('}','{');

    }
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        if((s.length() & 1) == 1){
            return false;
        }
        for(int i = 0; i < s.length(); i++){
            char c = s.charAt(i);
            if(map.containsKey(c)){
                char top = stack.isEmpty() ? '#' : stack.peek();
                if(top == map.get(c)){
                    stack.pop();
                }else{
                    return false;
                }
            }else{
                stack.push(c);
            }
        }
        return stack.isEmpty();
    }
}
  • 法三:最简(cyc大佬博客这里)
public boolean isValid(String s) {
    Stack<Character> stack = new Stack<>();
    for (char c : s.toCharArray()) {
        if (c == '(' || c == '{' || c == '[') {
            stack.push(c);
        } else {
            if (stack.isEmpty()) {
                return false;
            }
            char cStack = stack.pop();
            boolean b1 = c == ')' && cStack != '(';
            boolean b2 = c == ']' && cStack != '[';
            boolean b3 = c == '}' && cStack != '{';
            //b1、b2、b3有一个true
            if (b1 || b2 || b3) {
                return false;
            }
        }
    }
    return stack.isEmpty();
}

数组中元素与下一个比它大元素之间的距离

leetcode739每日温度

  • 法一:用栈保存数组元素
    在遍历数组时用栈把数组中的数存起来,如果当前遍历的数比栈顶元素来的大,说明栈顶元素的下一个比它大的数就是当前元素。

从左往右遍历

class Solution {
    public int[] dailyTemperatures(int[] T) {
        int len = T.length;
        int[] dist = new int[len];
        Stack<Integer> stack = new Stack<>();
        for (int i = 0; i < len; i++) {
            while (!stack.isEmpty() && T[i] > T[stack.peek()]) {
                int preIndex = stack.pop();
                dist[preIndex] = i - preIndex;
            }
            //stack本身没有add()方法,但是继承的类vector有add方法,同样vector的父类和实现接口List同样有add()方法。
            stack.add(i);
        }
        return dist;
    }
}

从右往左

class Solution {
    public int[] dailyTemperatures(int[] T) {
        int[] dist = new int[T.length];
        Stack<Integer> s = new Stack<>();
        for(int i = T.length-1; i >= 0; i--){
            while(!s.empty() && T[i] >= T[s.peek()]){
                s.pop();//将不大于当前元素的剔除
            }
            dist[i] = s.empty() ? 0 : (s.peek() - i);
            s.push(i);
        }
        return dist;
    }
}
  • 法二:从数组右边遍历,减少重复次数
class Solution {
    public int[] dailyTemperatures(int[] T) {
        int N = T.length;
        int[] dist = new int[N];
        Arrays.fill(dist,0);
        for(int i = N - 2; i >= 0; i--){
         // j+= dist[j]是利用已经有的结果进行跳跃
            for(int j = i + 1; j < N; j += dist[j]){
                if(T[j] > T[i]){
                    dist[i] = j - i;
                    break;
                }else if(dist[j] == 0){//遇到0表示后面不会有更大的值,那当然当前值就应该也为0
                    dist[i] = 0;
                    break;//不加的话会超出时间限制
                }
            }
        }
        return dist;
    }
}

循环数组中比当前元素大的下一个元素

leetcode503

class Solution {
    public int[] nextGreaterElements(int[] nums) {
        int N = nums.length;
        int[] result = new int[N];
        Arrays.fill(result,-1);
        Stack<Integer> s = new Stack<>();
        for(int i = 0; i < 2*N; i++){
            while(!s.isEmpty() && nums[i%N] > nums[s.peek()]){
                int pre = s.pop();
                result[pre] = nums[i%N];
            }
            if(i < N){
                s.push(i);
            }
        }
        return result;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值