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();
}
}
}