Leetcode算法系列一(栈、队列、堆)

225.用队列实现栈(栈、队列)(easy)

使用队列实现栈的下列操作:

push(x) – 元素 x 入栈
pop() – 移除栈顶元素
top() – 获取栈顶元素
empty() – 返回栈是否为空
注意:

你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。

import java.util.LinkedList;
import java.util.Queue;

public class MyStack {
    Queue<Integer> data=new LinkedList<>();
    /** Initialize your data structure here. */
    public MyStack() {

    }

    /** Push element x onto stack. */
    public void push(int x) {
        Queue<Integer> temp=new LinkedList<>();
        temp.add(x);
        while(!data.isEmpty()){
            temp.add(data.remove());
        }
        while(!temp.isEmpty()){
            data.add(temp.remove());
        }
    }

    /** Removes the element on top of the stack and returns that element. */
    public int pop() {
        return data.remove();
    }

    /** Get the top element. */
    public int top() {
        return  data.peek();
    }

    /** Returns whether the stack is empty. */
    public boolean empty() {
        return data.isEmpty();
    }
}

232. 用栈实现队列(栈、队列)(easy)

使用栈实现队列的下列操作:

push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。

示例:

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);
queue.peek(); // 返回 1
queue.pop(); // 返回 1
queue.empty(); // 返回 false

说明:

你只能使用标准的栈操作 – 也就是只有 push to top, peek/pop from top, size, 和 is empty 操作是合法的。
你所使用的语言也许不支持栈。你可以使用 list 或者 deque(双端队列)来模拟一个栈,只要是标准的栈操作即可。
假设所有操作都是有效的 (例如,一个空的队列不会调用 pop 或者 peek 操作)。

import java.util.Stack;

public class MyQueue {
    Stack<Integer> data=new Stack<>();
    /** Initialize your data structure here. */
    public MyQueue() {

    }

    /** Push element x to the back of queue. */
    public void push(int x) {
        Stack<Integer> temp=new Stack<>();
        while(!data.empty()){
            temp.add(data.pop());
        }
        temp.add(x);
        while(!temp.empty()){
            data.add(temp.pop());
        }
    }

    /** Removes the element from in front of queue and returns that element. */
    public int pop() {
        return data.pop();
    }

    /** Get the front element. */
    public int peek() {
        return data.peek();
    }

    /** Returns whether the queue is empty. */
    public boolean empty() {
        return data.empty();
    }
}

剑指 Offer 30. 包含min函数的栈(栈)(easy)

定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min、push 及 pop 的时间复杂度都是 O(1)。

示例:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.min(); --> 返回 -3.
minStack.pop();
minStack.top(); --> 返回 0.
minStack.min(); --> 返回 -2.

提示:

各函数的调用总次数不超过 20000 次

import java.util.Stack;

public class MinStack {
    Stack<Integer> data=new Stack<>();
    Stack<Integer> min=new Stack<>();
    /** initialize your data structure here. */
    public MinStack() {

    }

    public void push(int x) {
        data.add(x);
        if(min.empty()){
            min.add(x);
        }else{
            if(x>min.peek()){
                x=min.peek();
            }
            min.add(x);
        }
    }

    public void pop() {
        data.pop();
        min.pop();
    }

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

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

946.验证栈序列(栈、队列)(medium)

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

示例 1:

输入:pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
输出:true
解释:我们可以按以下顺序执行:
push(1), push(2), push(3), push(4), pop() -> 4,
push(5), pop() -> 5, pop() -> 3, pop() -> 2, pop() -> 1
示例 2:

输入:pushed = [1,2,3,4,5], popped = [4,3,5,1,2]
输出:false
解释:1 不能在 2 之前弹出。

提示:

0 <= pushed.length == popped.length <= 1000
0 <= pushed[i], popped[i] < 1000
pushed 是 popped 的排列。

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class Solution {
    public boolean validateStackSequences(int[] pushed, int[] popped) {
        int j=0;
        Stack<Integer> s=new Stack<>();
        int n=pushed.length;
        
        for(int i=0;i<n;i++){
            s.add(pushed[i]);
            while(!s.empty()&&s.peek()==popped[j]){
                s.pop();
                j++;
            }
        }
            if(!s.empty()){
                return false;
            }
            return true;
    }
}

224. 基本计算器(栈)(hard)

实现一个基本的计算器来计算一个简单的字符串表达式的值。

字符串表达式可以包含左括号 ( ,右括号 ),加号 + ,减号 -,非负整数和空格 。

示例 1:

输入: “1 + 1”
输出: 2
示例 2:

输入: " 2-1 + 2 "
输出: 3
示例 3:

输入: “(1+(4+5+2)-3)+(6+8)”
输出: 23
说明:

你可以假设所给定的表达式都是有效的。
请不要使用内置的库函数 eval。
在这里插入图片描述

215. 数组中的第K个最大元素(堆)(easy)

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

import java.util.PriorityQueue;

public class Solution {
    public int findKthLargest(int[] nums, int k) {
        PriorityQueue<Integer> minHeap=new PriorityQueue<>(k);//构建大小为k的最小堆,由前k大的元素构成
        for(int i:nums){
            if(minHeap.size()<k){
                minHeap.offer(i);
            }else if(i>minHeap.peek()){//该数大于最小堆的根,说明需要剔除第一个元素
                minHeap.poll();
                minHeap.offer(i);
            }
        }
        return minHeap.peek();
    }
   
}

295. 数据流的中位数(堆)(hard)

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3)
findMedian() -> 2
进阶:

如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?

易错点:

使用优先级队列时,忘记调整比较器(默认最小堆),导致错解。

解题思路:

看到这道题的第一眼,大家都可以想到使用快速排序来实现,但是每次查找中位数都需要快排一次,这提高了算法的时间复杂度。
为了减少时间复杂度,我们可以使用把数据流分成两部分,前有序数据流和后有序数据流。我们可以取前数据流的最大值(即最大堆的根结点)和后数据流的最小值(即最小堆的根结点)作为中位数的相关数据。
所以,以下会使用最大堆和最小堆来实现这个算法,同时要保证最大堆的根元素小于最小堆的根元素。

1.添加数据

有以下4种情况(1,2,3情况如上图):
0.最小堆和最大堆都是空的,往任意一个堆添加元素即可
1.最小堆和最大堆元素个数相等:

  • 1.1当新元素大于最大堆的根元素,将新元素加入最小堆(保证最大堆的根元素小于最小堆的根元素)
  • 1.2当新元素小于最大堆的根元素,将新元素加入最大堆

2.最小堆个数小于最大堆个数

  • 2.1当新元素大于最大堆的根元素,将新元素加入最小堆
  • 2.2当新元素小于最大堆的根元素,将最大堆的根元素移动到最小堆,将新元素加入最大堆。

3.最大堆个数小于最小堆个数

  • 情况和第2点相反。
2.寻找中位数

1.元素个数相等,两个堆的根结点之和除以2.
2.元素个数不等,取元素个数最多的堆相应的根结点即可。

代码:

import java.text.DecimalFormat;
import java.util.PriorityQueue;

public class MedianFinder {

    PriorityQueue<Integer> minHeap=new PriorityQueue<>();//最小堆,根元素大于最大堆的根元素
    PriorityQueue<Integer> maxHeap=new PriorityQueue<>((x,y)->y-x);//最大堆,根元素小于最小堆的根元素
    /** initialize your data structure here. */
    public MedianFinder() {

    }

    public void addNum(int num) {
        if(maxHeap.size()==0&&minHeap.size()==0){
            maxHeap.offer(num);
        }else if(maxHeap.size()==minHeap.size()){
            if(num>maxHeap.peek()){
                minHeap.offer(num);
            }else{
                maxHeap.offer(num);
            }
        }else if(maxHeap.size()>minHeap.size()){
            if(num>maxHeap.peek()){
                minHeap.offer(num);
            }else{
                minHeap.offer(maxHeap.poll());
                maxHeap.offer(num);
            }
        }else{
            if(num<minHeap.peek()){
                maxHeap.offer(num);
            }else{
                maxHeap.offer(minHeap.poll());
                minHeap.offer(num);
            }
        }
    }

    public double findMedian() {
        if(maxHeap.size()==minHeap.size()){
            return 1.0*(maxHeap.peek()+minHeap.peek())/2;
        }
        return maxHeap.size()>minHeap.size()?maxHeap.peek():minHeap.peek();
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值