用两个栈实现队列
//需要考虑S2是否为空
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
//队列的压入就是s1的压入数据
public void push(int node) {
stack1.push(node);
}
//弹出借助于S1/s2 两个 弹出需要考虑队列是否为空
public int pop() {
if(size()!=0){
if(stack2.empty()){ //若s2为空 则需要把s1的元素全部压入s2再输出
while(!stack1.empty())
stack2.push(stack1.pop());
}
return stack2.pop(); //若s2不为空 则直接输出
}else{
System.out.println("队列为空,不能执行出队操作");
return -1;
}
}
//队列的大小 队列为空则说明 s1/s2均为空
public int size(){
return stack1.size()+stack2.size();
}
}
用两个队列实现一个栈
import java.util.*;
/**
* 使用LinkedList表示队列 所以队列从尾入队 q1.addLast(e) 从头出队q1.removeFirst()
* @author 多多
*
* @param <E>
*/
public class MyStack<E> {
LinkedList<E> q1=new LinkedList<E>(); //队列1
LinkedList<E> q2=new LinkedList<E>(); //队列2
//入栈操作 即入队
public void push(E e) {
q1.addLast(e); //从尾部入队
}
//出栈操作: 非空队列的n-1个压入空队列 剩余的第n个出队 总有一个队列为空
public E pop() {
if(size()!=0) { //判断栈是否为空
if(!q1.isEmpty()) {
putN_1ToAnother(); //非空队列的n-1个压入空队列
return q1.removeFirst(); //剩余的第n个出队 (从对头出队)
}else {
putN_1ToAnother();
return q2.removeFirst();
}
}else {
System.out.println("栈为空,无法执行出栈操作");
return null;
}
}
// 非空队列的n-1个压入空队列
private void putN_1ToAnother() {
if(!q1.isEmpty()) { //若q2为空 则从q1中移动前n-1个
while(q1.size()>1) {
q2.addLast(q1.removeFirst());
}
}else {
while(q2.size()>1) { //若q1为空 则从q2中移动前n-1个
q1.addLast(q2.removeFirst());
}
}
}
//判断栈是否为空
public int size() {
return q1.size()+q2.size();
}
}
包含min函数的栈
方法1: 每次都存入
import java.util.Stack;
public class Solution {
private Stack<Integer> stackDate;
private Stack<Integer> stackMin;
public Solution(){
stackDate = new Stack<>();
stackMin = new Stack<>();
}
public void push(int node) {
stackDate.push(node);
if(stackMin.isEmpty()){
stackMin.push(node);
}else if(node <= stackMin.peek()){
stackMin.push(node);
}
}
public void pop() {
if(stackDate.isEmpty()){
throw new RuntimeException("This stack is empty!");
}
if(stackDate.peek() == stackMin.peek()){
stackMin.pop();
}
stackDate.pop();
}
public int top() {
if(stackDate.isEmpty()){
throw new RuntimeException("This stack is empty!");
}
int value = stackDate.pop();
if(value == stackMin.peek()){
stackMin.pop();
}
return value;
}
public int min() {
if(stackMin.isEmpty()){
throw new RuntimeException("This stack is empty!");
}else{
return stackMin.peek();
}
}
}
方法2:只存入比之前小的元素
import java.util.Stack;
public class Solution {
private Stack<Integer> stackDate;
private Stack<Integer> stackMin;
public Solution(){
stackDate = new Stack<Integer>();
stackMin = new Stack<Integer>();
}
public void push(int node) {
stackDate.push(node);
if(stackMin.isEmpty()){
stackMin.push(node);
}else if(node <= stackMin.peek()){
stackMin.push(node);
}
}
public void pop() {
if(stackDate.empty()){
throw new RuntimeException("This stack is empty!");
}
if(stackDate.peek() == stackMin.peek()){ //相同则一起弹出
stackMin.pop();
}
stackDate.pop(); //否则只是弹出数据栈
}
public int top() { //获取栈顶元素
if(stackDate.isEmpty()){
throw new RuntimeException("This stack is empty!");
}
int value = stackDate.pop();
if(value == stackMin.peek()){
stackMin.pop();
}
return value;
}
public int min() {
if(stackMin.isEmpty()){
throw new RuntimeException("This stack is empty!");
}else{
return stackMin.peek();
}
}
}
栈的压入 ,弹出序列
方法1: Stack结构辅助
import java.util.ArrayList;
import java.util.Stack;
public class Solution {
public boolean IsPopOrder(int [] pushA,int [] popA) {
if(pushA.length==0 || popA.length==0|| pushA.length!=popA.length)
return false;
Stack<Integer> s=new Stack<Integer>();
int index=0; //pop数组的下标
for(int i=0;i<pushA.length;i++){
s.push(pushA[i]); //压入元素
//判断 当s非空 且栈顶元素等于pop[index]时则弹出
while(!s.empty() && s.peek()==popA[index]){
s.pop();
index++;
}
}
return s.empty(); //正常则全部弹出 为空 否则为不正确的输出序列
}
}
//注意一个地方:
while(index<popA.length && s.peek()==popA[index]){ //这个就是防止两个数组均对应输出完毕 出现栈为空 却要弹出的情况
s.pop();
index++;
}
滑动窗口的最大值:
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
方法1 :时间O(n2) 两个for截取特定区间比较储存
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
//采用时间复杂度为O(n2)的笨办法
ArrayList<Integer> list=new ArrayList<Integer>();
if(num==null || num.length==0 || size<=0 || size> num.length)
return list;
int len=num.length;
for(int i=0;i<len-size+1;i++){
int max=Integer.MIN_VALUE;
for(int j=i;j< i+size; j++){ //注意这个区间截取范围
if(max< num[j])
max=num[j];
}
list.add(max);
}
return list;
}
}
方法2 :时间O(n) 空间O(n) 采用队列的思想
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> list=new ArrayList<Integer>();
if(num==null || num.length==0 || size<=0 || size> num.length)
return list;
int len=num.length;
//采用队列的思想 入队一个出队一个
Queue<Integer> q=new LinkedList<Integer>();
int max=Integer.MIN_VALUE;
//对于前size个元素 直接一次入队列
for(int i=0;i<size;i++){
q.add(num[i]);
if(max <num[i])
max=num[i];
}
list.add(max);
//之后每次弹出一个 就进入一个 并在其中取最大值
for(int i=size;i<len;i++){
q.poll();
q.add(num[i]);
max=Integer.MIN_VALUE;
for(Integer n: q){
if(max< n)
max=n;
}
list.add(max);
}
return list;
}
}
方法3 :时间,空间均为O(n) 采用“双端队列”的思想
原则:
* 对新来的元素k,将其与双端队列中的元素相比较
* 1)前面比k小的,直接移出队列(因为不再可能成为后面滑动窗口的最大值了!),
* 2)前面比k大的X,比较两者下标,判断X是否已不在窗口之内,不在了,直接移出队列
* 队列的第一个元素是滑动窗口中的最大值
import java.util.*;
public class Solution {
public ArrayList<Integer> maxInWindows(int [] num, int size)
{
ArrayList<Integer> list=new ArrayList<Integer>();
if(num==null || num.length==0 || size<=0 || size> num.length)
return list;
int len=num.length;
//采用队列的思想 入队一个出队一个
LinkedList<Integer> q=new LinkedList<Integer>(); //队列存储的是下标
for(int i=0;i<len;i++){
//从后面依次弹出队列中比当前num值小的元素 则当前队列首元素即为当前窗口的最大值
while(!q.isEmpty() && num[q.peekLast()]<= num[i]){ //注意队列不为空的判断!!因为第一次是没有元素的,会主动跳过两个判断
q.pollLast();
}
//当前窗口首元素位置移出当前窗口 则删除首元素
while(!q.isEmpty() && i-q.peekFirst()>size-1){
q.pollFirst();
}
q.addLast(i); //将每一个num值入队
if(size!=0 && i>=size-1){ //当i >=size-1时才开始写入窗口最大值
list.add(num[q.peekFirst()]);
}
}
return list;
}
}