算法 - 数组 | 栈 | 队列
使用数组模拟栈和队列
使用数组模拟栈,包括栈的 push、pop 和 peek 操作。
public class ArrayStack {
private Integer[] arr;
private Integer size;
public ArrayStack(int initSize) {
if (initSize < 0) {
throw new IllegalArgumentException("栈的大小不能小于 0");
}
arr = new Integer[initSize];
size = 0;
}
public Integer peek() {
if (size == 0) {
return null;
}
return arr[size - 1];
}
public void push(Integer number) {
if (size == arr.length) {
throw new ArrayIndexOutOfBoundsException("栈已满!");
}
arr[size++] = number;
}
public Integer pop() {
if (size == 0) {
throw new ArrayIndexOutOfBoundsException("栈已空!");
}
return arr[--size];
}
}
使用数组模拟队列,包括队列的 offer、poll 和 peek 操作。
public class ArrayQueue {
private Integer[] arr;
private Integer size;
private Integer first;
private Integer last;
public ArrayQueue(int initSize) {
if (initSize < 0) {
throw new IllegalArgumentException("队列长度不能小于 0!");
}
arr = new Integer[initSize];
size = 0;
//first 指向队首的位置
first = 0;
//last 指向队尾后空的位置
last = 0;
}
public void offer(int number) {
if (size == arr.length) {
throw new ArrayIndexOutOfBoundsException("队列已满!");
}
arr[last++] = number;
last = last < arr.length ? last : 0;
size++;
}
public Integer poll() {
if (size == 0) {
throw new ArrayIndexOutOfBoundsException("队列已空!");
}
int res = arr[first++];
first = first < arr.length ? first : 0;
size--;
return res;
}
public Integer peek() {
if (size == 0) {
return null;
}
return arr[first];
}
}
设计 getMin() 操作时间复杂度为 O(1) 的栈
设计一个栈,获取栈内最小值操作为 O(1),兼具栈的 push、pop 功能。
public class MyStack {
private Stack<Integer> stackData;
private Stack<Integer> stackMin;
public MyStack() {
this.stackData = new Stack<>();
this.stackMin = new Stack<>();
}
public void push(int number) {
if (this.stackMin.isEmpty()) {
this.stackMin.push(number);
} else {
int temp = this.stackMin.peek();
if (temp < number) {
this.stackMin.push(temp);
} else {
this.stackMin.push(number);
}
}
this.stackData.push(number);
}
public Integer pop() {
if (this.stackData.isEmpty()) {
throw new RuntimeException("栈已空!");
}
this.stackMin.pop();
return this.stackData.pop();
}
public Integer getMin() {
if (this.stackData.isEmpty()) {
throw new RuntimeException("栈已空!");
}
return this.stackMin.peek();
}
}
使用栈实现队列
stack1 专门用来添加数据 offer(),stack2 专门用来查看和弹出数据 peek() poll()。
addStack2() 有两个前提:
- stack1 非空
- stack1 需要将所有数据转移到 stack2
public class StackToQueue {
private Stack<Integer> stack1;
private Stack<Integer> stack2;
public StackToQueue() {
this.stack1 = new Stack<>();
this.stack2 = new Stack<>();
}
public void offer(int number) {
this.stack1.push(number);
addStack2();
}
public Integer peek() {
if (this.stack2.isEmpty()) {
return null;
}
return this.stack2.peek();
}
private void addStack2() {
while (!this.stack1.isEmpty()) {
this.stack2.push(this.stack1.pop());
}
}
public Integer poll() {
if (this.stack2.isEmpty()) {
throw new RuntimeException("队列已空!");
}
return this.stack2.pop();
}
}
使用队列实现栈
使用两个队列,一个是存储队列,一个是 help 队列。
helper()
- 将 queue 队列的数据转移到 help 队列中,只留下 queue 队列尾部的一个元素作为返回值
swap()
- 将 queue 队列和 help 队列的引用互换
public class QueueToStack {
private Queue<Integer> queue;
private Queue<Integer> help;
public QueueToStack() {
this.queue = new LinkedList<>();
this.help = new LinkedList<>();
}
public void push(int number) {
queue.offer(number);
}
public Integer peek() {
if (queue.isEmpty()) {
return null;
}
int res = helper();
help.offer(res);
swap();
return res;
}
//将数据从 queue 转移到 help 中,留下一个数
private Integer helper() {
while (queue.size() > 1) {
help.offer(queue.poll());
}
return queue.poll();
}
private void swap() {
Queue<Integer> temp = queue;
queue = help;
help = temp;
}
public Integer pop() {
if (queue.isEmpty()) {
throw new RuntimeException("栈已空");
}
int res = helper();
swap();
return res;
}
}
猫狗队列问题
经典的问题,不赘述。思路是先将 Pet 这个类包装一下,打上时间戳,增加了一个变量 count。
class PetEntry {
private Pet pet;
private long count;
public PetEntry(Pet pet, long count) {
this.pet = pet;
this.count = count;
}
public Pet getPet() {
return this.pet;
}
public long getCount() {
return this.count;
}
public String getEntryPetType() {
return this.pet.getPetType();
}
}
然后将获得的一个个 PetEntry 对象添加到队列中,在添加的时候就会对 PetEntry 对象的类型做判断,如果是 Cat 类就进入 catQ,如果是 Dog 类就进入 dogQ。
public class DogCatQueue {
private Queue<PetEntry> dogQ;
private Queue<PetEntry> catQ;
private long count;
public DogCatQueue() {
this.dogQ = new LinkedList<>();
this.catQ = new LinkedList<>();
this.count = 0;
}
public void add(Pet pet) {
if (pet.getPetType().equals("dog")) {
this.dogQ.offer(new PetEntry(pet, this.count++));
} else if (pet.getPetType().equals("cat")) {
this.catQ.offer(new PetEntry(pet, this.count++));
} else {
throw new RuntimeException("宠物需为猫或狗");
}
}
public Pet pollAll() {
if (!this.dogQ.isEmpty() && !this.catQ.isEmpty()) {
if (this.dogQ.peek().getCount() < this.catQ.peek().getCount()) {
return this.dogQ.poll().getPet();
} else {
return this.catQ.poll().getPet();
}
} else if (this.dogQ.isEmpty()) {
return this.catQ.poll().getPet();
} else if (this.catQ.isEmpty()) {
return this.dogQ.poll().getPet();
} else {
throw new RuntimeException("队列已空!");
}
}
public Dog pollDog() {
if (this.dogQ.isEmpty()) {
throw new RuntimeException("狗队列为空!");
}
return (Dog) this.dogQ.poll().getPet();
}
public Cat pollCat() {
if (this.catQ.isEmpty()) {
throw new RuntimeException("猫队列为空!");
}
return (Cat) this.catQ.poll().getPet();
}
public boolean isEmpty() {
return this.dogQ.isEmpty() && this.catQ.isEmpty();
}
public boolean isDogQueueEmpty() {
return this.dogQ.isEmpty();
}
public boolean isCatQueueEmpty() {
return this.catQ.isEmpty();
}
}
严格来说这不是一个算法题目,而是一个工程类题目,使用了装饰者设计模式,对原有的类进行包装,成为一个 Entry 类。