算法 - 数组 | 栈 | 队列

使用数组模拟栈和队列

使用数组模拟栈,包括栈的 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 类。

posted @ 2019-11-23 17:47  学习趁早  阅读(156)  评论(0编辑  收藏  举报