直接上干货。。。。。
栈和队列常见题型:
- 实现栈和实现队列。
- 两个栈实现一个队列。
- 设计栈,使得pop,push和min时间复杂度为O(1)。
- 滑动窗口的最大值。
- 栈的进出序列。
实现栈和实现队列
主要包括:栈,队列,循环队列。
package com.sywyg;
/**
* 实现栈
* 数组应该是Object类型的
* 注意top的设置影响出栈和获取栈顶元素。
* size也可以用top代替
*/
class MyStack<E>{
// 栈元素个数
private int size;
// 栈头
private int top;
// 数组保存元素
private Object[] stack = null;
public MyStack(int length){
stack = new Object[length];
top = 0;
}
public int size(){
return size;
}
// 进栈
public void push(E e){
if(size == stack.length){
try{
throw new Exception("栈已满");
}catch(Exception ex){
ex.printStackTrace();
}
}
stack[top++] = e;
size++;
}
// 出栈
public E pop(){
E e = null;
if(size == 0){
try{
throw new Exception("栈为空");
}catch(Exception ex){
ex.printStackTrace();
}
}
e = (E)stack[--top];
size--;
return e;
}
// 获取栈顶元素
public E top(){
if(size == 0){
try{
throw new Exception("栈为空");
}catch(Exception e){
e.printStackTrace();
}
}
return (E)stack[top-1];
}
}
/**
* 创建队列,这种队列会造成假溢出
*/
class MyQueue<E>{
// 队列长度
private int size;
// 队头
private int front;
// 队尾
private int back;
private Object[] queue;
public MyQueue(int length){
queue = new Object[length];
size = 0;
front = 0;
back = 0;
}
public int size(){
return size;
}
// 进队
public void enqueue(E e){
if(size == queue.length){
try{
throw new Exception("队已满");
}catch(Exception ex){
ex.printStackTrace();
}
}
queue[back++] = e;
size++;
}
// 出队
public E dequeue(){
E e = null;
if(size == 0 || back == front){
try{
throw new Exception("队为空");
}catch(Exception ex){
ex.printStackTrace();
}
}
e = (E)queue[front++];
size--;
return e;
}
// 返回队头
public E front(){
return (E)queue[front];
}
// 返回队尾?
public E back(){
return (E)queue[back - 1];
}
}
/**
* 循环队列,采用浪费一个位置(使用size可以保证全利用)
* 这里不使用size标记队列的长度,尽管这种方式很简单
*/
class LoopQueue<E>{
// 队头
private int front;
// 队尾
private int back;
private Object[] queue;
public LoopQueue(int length){
// 浪费一个
queue = new Object[length + 1];
front = 0;
back = 0;
}
public int size(){
return (back - front + queue.length)% queue.length;
}
// 进队
public void enqueue(E e){
if((front - back + queue.length)% queue.length == 1){
try{
throw new Exception("队已满");
}catch(Exception ex){
ex.printStackTrace();
}
}
queue[back ++ % queue.length] = e;
}
// 出队
public E dequeue(){
E e = null;
if(front == back){
try{
throw new Exception("队为空");
}catch(Exception ex){
ex.printStackTrace();
}
}
e = (E)queue[front++ % queue.length];
return e;
}
// 返回队头
public E front(){
return (E)queue[front];
}
// 返回队尾?
public E back(){
return (E)queue[(back - 1 + queue.length) % queue.length];
}
}
两个栈实现一个队列
思想:一个栈A只进,一个栈B只出,B为空则A元素进入B,再出栈。
package com.sywyg;
/**
* 两个栈实现一个队列。
* 这样仍然会造成假溢出。
*
*
*/
public static class Solution<E>{
// 应该在构造器中赋值。
// stack1用来入队
private Stack<E> stack1 = new Stack<E>();
// stack2用来出队
private Stack<E> stack2 = new Stack<E>();
// 入队
public void enqueue(E e){
stack1.push(e);
//System.out.println("此时stack1栈顶元素为:" + stack1.top());
}
// 出队
public E dequeue(){
E e = null;
if(stack2.size() != 0){
e = stack2.pop();
}else if(stack1.size() != 0){
int length = stack1.size();
for(int i = 0;i<length;i++){
stack2.push(stack1.pop());
//System.out.println("此时stack2栈顶元素为:" + stack2.top());
}
e = stack2.pop();
}
return e;
}
}
- 测试:进进出出,进出。
- 如何用两个队列实现一个栈。
#设计栈,使得pop,push和min时间复杂度为O(1)
思想:额外的栈A存放当前最小值,每当进来的值a小于/等于该栈顶值b时,a需要入栈A;出栈时若栈A的栈顶和刚出栈的元素相等时,则A也出栈。
```java
package com.sywyg;
import java.util.Stack;
/**
* 设计栈,使得pop,push和min时间复杂度为O(1)。
* 或者使用一个每个最小值再包含一个计数标记
*/
public static class Solution<E>{
private Stack<E> stack,stackMin;
public Solution(){
stack = new Stack<E>();
stackMin = new Stack<E>();
}
// 入栈
public void push(E e){
stack.push(e);
if(stackMin.isEmpty()){
stackMin.push(e);
}else if(stackMin.peek() >= e){
stackMin.push(e);
}
}
// 出栈
public E pop(){
E e = stack.pop();
if(e == stackMin.peek()){
stackMin.pop();
}
}
// 返回最小
public E min(){
return stackMin.peek();
}
}
<div class="se-preview-section-delimiter"></div>
- 测试:小大大大小小,每次出栈判断是否正确。
- 时间复杂度:O(1),空间复杂度O(n)
滑动窗口的最大值
给定一个数组,和滑动窗口的大小,计算每个窗口中的最大值。例如数组{1,2,3,4,5},窗口大小为3。那么共存在3个滑动窗口,它们的大小为:{3,4,5}。
思想:须用到上面的第2题和第3题,用两个能够O(1)时间内计算出最大值的栈实现队列。先进入3个(窗口大小),然后再依次进1出1个。在统计最大值的时候比较两个栈中的最大值即可,注意需要判断栈是否为空。
package com.sywyg;
import java.util.Stack;
/**
* 滑动窗口的最大值。
* @author sywyg
* 测试
*/
public class Question4 {
public static void main(String[] args) {
int[] array = {2,3,4,2,6,5,2,1};
int[] max = solution(array, 3);
for (int i = 0; i < max.length; i++) {
System.out.println(max[i]);
}
}
public static int[] solution(int[] array,int size){
int[] max = new int[array.length - size + 1];
MyQueue<Integer> queue = new MyQueue<Integer>();
int i = 0;
for(i = 0; i<size; i++){
queue.enqueue(array[i]);
}
int j = 0;
// 先进一个
max[j++] = queue.stack1.max();
for(;i<array.length;i++){
queue.dequeue();
queue.enqueue(array[i]);
// 两个栈中的最大值进行比较
if(queue.stack2.stackMax.size() == 0 || queue.stack1.max() >= queue.stack2.max()){
max[j++] = queue.stack1.max();
}else
max[j++] = queue.stack2.max();
}
return max;
}
/**
* 两个栈实现队列
*/
public static class MyQueue<E>{
// 应该在构造器中赋值。
// stack1用来入队
public MyStack<E> stack1 = new MyStack<E>();
// stack2用来出队
public MyStack<E> stack2 = new MyStack<E>();
// 入队
public void enqueue(E e){
stack1.push(e);
//System.out.println("此时stack1栈顶元素为:" + stack1.top());
}
// 出队
public E dequeue(){
E e = null;
if(stack2.size() != 0){
e = stack2.pop();
}else if(stack1.size() != 0){
int length = stack1.size();
for(int i = 0;i<length;i++){
stack2.push(stack1.pop());
//System.out.println("此时stack2栈顶元素为:" + stack2.top());
}
e = stack2.pop();
}
return e;
}
}
/**
* pop(),push(),max() 复杂度为O(1)
*/
public static class MyStack<E>{
public Stack<E> stack,stackMax;
public MyStack(){
stack = new Stack<E>();
stackMax = new Stack<E>();
}
// 入栈
public void push(E e){
stack.push(e);
if(stackMax.isEmpty()){
stackMax.push(e);
}else if((Integer)stackMax.peek() <= (Integer)e){
stackMax.push(e);
}
}
// 出栈
public E pop(){
E e = stack.pop();
if(e == stackMax.peek()){
stackMax.pop();
}
return e;
}
// 返回最大
public E max(){
return stackMax.peek();
}
public E peek(){
return stack.peek();
}
public int size(){
return stack.size();
}
}
}
<div class="se-preview-section-delimiter"></div>
- 测试:有大有小的输入。
- 时间复杂度:O(n)
栈的进出序列
输入进栈的顺序判断给出的出栈顺序是否正确。
思想:先进栈,然后判断是否和给出的顺序相等。若不相等则继续进栈判断,直到进完;若相等则继续出栈判断,直到出完。
package com.sywyg;
import java.util.Stack;
/**
* 栈的进出序列
* @author sywyg
* @since 2015.7.25
* 测试:
*/
public class Question5 {
public static void main(String[] args) {
Question5 question = new Question5();
int[] array1 = {1,2,3,4,7};
int[] array2 = {3,1,2,5,0};
System.out.println(question.solution(array1, array2));
}
// 第一个参数为输入顺序,第二个参数为要判断的输出结果
public boolean solution(int[] array1,int[] array2){
// 健壮性判断
if(array1 == null || array2 == null) return false;
if(array1.length != array2.length) return false;
Stack<Integer> stack = new Stack<Integer>();
int i = 0,j = 0;
for (; i < array1.length; i++) {
stack.push(array1[i]);
while(stack.size() != 0 && stack.peek() == array2[j]) {
stack.pop();
j++;
}
}
return j == i?true:false;
}
}
- 测试:给出正确的,给出错误的,给出不相等的数组。
- 时间复杂度:O(n)
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-11 09:15:28