Cracking the Code Interview Chapter Three-- TaylorZhangYuxin's Solusion

This article is my own thinking and analysis when reading the cracking the code interview 6th edition.

Chapter 3 Stacks and Queues

3.1 Describe how you could use a single array to implement three stacks.

Analysis:

If we use a single array to implement one stack, we use index to keep track the data. When push into the stack, we increment the index by one. When pop, we decrement the index. Enlarge the array when the index exceeds the max length.
Now we implement three stacks. Each stack entitled with ID number 1, 2, 3. For stack 1, we use index1 to keep track the data in the array. For stack 2, we use 2*index2 to keep track the data in the array. For stack 3, we use 3*index3 to keep track the data.
The array will enlarge with the stack grows.

private static final Exception NotValidStackID = null;
    private static final Exception EmptyStack = null;
    int index1 = 0;
    int index2 = 0;
    int index3 = 0;
    int size = 1;
    int[] database = new int[3*size];


    public ChapterThree01 () {
        // TODO Auto-generated constructor stub
        int index = 0;
        int size = 1;
        int[] database = new int[size];

    }

    public boolean push (int n, int ID) throws Exception{
        if(index1+1 > size || index2+1 > size || index3+1 > size){
            int[] newbase = new int[2*3*size];
            for(int i = 0; i < 3*size; i ++){
                newbase[i] = database[i];
                database = newbase;
            }
        }

        switch (ID){
        case 1:
            database[3*index1] = n;
            index1 ++;
            break;
        case 2:
            database[3*index2+1] = n;
            index2++;
            break;
        case 3:
            database[3*index3 + 2] = n;
            index3++;
            break;
            default:
                throw NotValidStackID;
        }

        return true;
    }

    public int pop(int n, int ID) throws Exception{
        if (isEmpty(ID) == true) throw EmptyStack;
        int popdata = 0;
        switch(ID){
        case 1:
            popdata = database[3*index1];
            index1--;
            return popdata;
        case 2:
            popdata = database[3*index2+1];
            index2--;
            return popdata;
        case 3:
            popdata = database[3*index3+2];
            index3--;
            default:
                throw NotValidStackID;
        }
    }

    public boolean isEmpty(int ID) throws Exception{
        switch (ID){
        case 1:
            if(index1 ==0) return true;
            else return false;
        case 2:
            if(index2 == 0) return true;
            else return false;
        case 3:
            if(index3 == 0) return true;
            else return false;
            default:
                throw NotValidStackID;
        }
    }

    public int peak(int ID) throws Exception{
        switch(ID){
        case 1:
            return database[3*index1];
        case 2:
            return database[3*index2+1];
        case 3:
            return database[3*index3+2];
            default:
                throw NotValidStackID;
        }
    }

3.2 How would you design a stack which, in addition to push and pop, has a function min which returns the minimum element? Push, pop and min should all operate in O (1) time.

Analysis:

Min remembers the min element in the stack. When push elements in the stack, it’s easy to keep track of the min element that comparing the new elements with the old one. However, when pop a min element, It’s hard to keep track of the min element without comparing the whole stack to find the min.
One thing I notice is that the order that data stores into the stack is fixed. So when given data was pushed out of the stack, the min is known for it has already there when push was run.
Solution explanation:
When store the data in the stack, give the data a min with it. Which means, use two stack to store data and min. When push the data in, calculate the new min with the old min, update it into the min stack. When pop the data out, pop the min data and return the former min, which is the min of the previous one.

private static class StackNode<T>{
        private T data;
        private T min;
        private StackNode<T> next;
        public StackNode(T data){
            this.data = data;
        }
    }

    private StackNode<T> top;

    public T pop(){
        if(top == null) throw new EmptyStackException();
        T item = top.data;
        top = top.next;
        return item;
    }

    public void push(T item){
        StackNode<T> t = new StackNode<T> (item);
        if(item < top.min) t.min = item; //Here we have an assumption that T must be a comparable type
        else t.min = top.min;
        t.next = top;
        top = t;
    }
    public T peek(){
        if(top == null){
            throw new EmptyStackException();
        }
        return top.data;
    }
    public boolean isEmpty(){
        return top == null;
    }
    public T min(){
        return top.min;
    }


    public ChapterThree02() {
        // TODO Auto-generated constructor stub

    }

3.3 Imagine a stack of plates. If the stack gets too high, it might topple. Therefore, in real list, we would likely start a new stack when the previous stack exceeds some threshold. Implement a data structure SetOfStacks that mimics this. SetOfstacks should be composed of several stacks and should create a new stack once the previous one exceeds capacity. SetOfStacks.push() and SetOfStacks.pop() should behave identically to a single stack.

Analysis:

In simple, the question asks us to do is combining many stacks together so that they performs like one. Here the hardest part is that how to keep track of the latest stack and how to create new stacks. The solution I come up with is to use LinkedList or Array to combine all stacks together.

Solution description:

I just use Linked list to implement this. When push, first check if the stack if full. If full, create a new stack and push this data into that stack. If not, just push data into current stack.
When pop, there are two things that need to take care. First is if the whole list is empty or if the first stack is empty, which equals the whole stack is empty. If yes, then throws empty stack exception. Second, if the list is not empty, but the current stack is empty. Then remove current stack, back to last stack and pop the data.
Also, the peek operation need to check both the list and the stack.

    final int capacity = 10;
    private LinkedList<StackForQ3<T>> stackHead = new LinkedList<StackForQ3<T>>();

    public void push(T item){
        if(stackHead.getLast().getLength() == capacity){
            StackForQ3<T> newStack = new StackForQ3<T>();
            newStack.push(item);
            stackHead.add(newStack);
        }
        else{
            stackHead.getLast().push(item);
        }
    }
    public T pop(){
        if(isEmpty()) throw new EmptyStackException();

        if(stackHead.getLast().isEmpty()){
            stackHead.removeLast();
        }
        return stackHead.getLast().pop();
    }
    public T peek(){
        if(isEmpty()) throw new EmptyStackException();

        return stackHead.getLast().peek();
    }
    public boolean isEmpty(){
        return stackHead.isEmpty() || stackHead.getFirst().isEmpty();
    }

    //FOLLOW UP
    public T popAt(int index){
        T popData = null;
        if(stackHead.get(index) == null) return null;
        if(stackHead.get(index).isEmpty()) return null;
        else popData = stackHead.get(index).pop();
        //check if current stack is empty, if yes, remove it
        if(stackHead.get(index).isEmpty()) stackHead.remove(index);
        return popData;
    }
FLLOW UP

Implement a function popAt(int index) which performs a pop operation on a specific sub-stack.
Analysis:
This function pops a specific data in sub-stack. One thing that need to make sure is that after this function, there must no empty stack in the list. Or there will be some complex checks through the code.

3.4 implement a MyQueue class which implements a queue using two stacks.

Analysis:

This question used to be a practice problem in class.
The only matter is the order that is different. To reach that, two stacks should perform different characters. One as the add stack and the second as the remove stack.
Solution description:
One Stack to hold new data. One to stack to hold the data that need to pop out.

    private Stacke<T> addstack = new Stacke<T>();
    private Stacke<T> removestack = new Stacke<T>();

    public void add(T data){
        addstack.push(data);
    }

    public T remove(){
        if(removestack.isEmpty()){
            if(addstack.isEmpty()) throw new EmptyStackException();
            while(!addstack.isEmpty()){
                removestack.push(addstack.pop());
            }
        }
        return removestack.pop();
    }

    public T peek(){
        if(removestack.isEmpty()){
            if(addstack.isEmpty()) throw new EmptyStackException();
            while(!addstack.isEmpty()){
                removestack.push(addstack.pop());
            }
        }
        return removestack.peek();
    }
    public boolean isEmpty(){
        return removestack.isEmpty() && addstack.isEmpty();
    }

3.5 Write a program to sort a stack such that the smallest items are on the top. You can use an additional temporary stack, but you may not copy the elements into any other data structure (such as an array). The stack supports the following operations: push, pop, peek and isEmpty.

Analysis:

Since the data was pushed one by one. As they pushed into the stack, we could do the sorting part. Every push only requires one single sorting process. Since the data was sorted in the stack, the pop, isEmpty and peek method would work as the old version.

Solution description:

As the data was moved from the original stack into new stack, they will be processed one by one. Make sure that every new data was placed in the right position in the sorted stack was the key thought in this solution. If the new data is smaller than the top data in the sorted stack, this data will be placed on the top of the sorted stack. If the new data is bigger than the top of the sorted stack, the sorted stack will pop out this smaller data into the original stack and continue comparing the data below with the new data until a bigger data was found or the sorted stack was empty, whichever happens first. Keep running the process until the original stack is empty which means all data in that stack is processed.

    public Stacke<Integer> sortStack(Stacke<Integer> dataBase){
        if(dataBase.isEmpty()) throw new EmptyStackException();
        Stacke<Integer> sortBase = new Stacke<Integer>();
        int tempMin = dataBase.pop();
        sortBase.push(tempMin);
        while(!dataBase.isEmpty()){
            tempMin = dataBase.pop();
            if(sortBase.peek() >= tempMin){
                sortBase.push(tempMin);
            }
            else{
                while((!sortBase.isEmpty())&&(sortBase.peek() < tempMin))
                {dataBase.push(sortBase.pop());}
                sortBase.push(tempMin);
            }
        }

        return sortBase;
    }

3.6 An animal shelter, which holds only dogs and cats, operates on a strictly “first in, first out” basis. People must adopt either the “oldest” (based on arrival time) of all animals at the shelter, or they can select whether they would prefer a dog or cat (and will receive the oldest animal of that type). They cannot select which specific animal they would like. Create the data structures to maintain this system and implement operations such as enqueue, dequeueany, dequueueDog, and dequeueCat. You may use the build-in LinkedList data structure.

Analysis:

The key in this question is create a linked list which the nodes are connected together. The function for this data structure is pretty like a queue. However, this queue has 2 dequeue exits. So there are 3 kinds of nodes in this structure. AnyNode, which holds the whole data list, CatNode, holds the data in Cat type. DogNode, holds the data in Dog type.
In the method enqueue, the type must be specified, so 2 arguments are accepted.
2 solutions are available.
1 kind of nodes with 3 kinds of next link, any, dog and cat.

This solution is worse for every time it enqueue a new data, it is required to check all node before to maintain the next.

1 kind of node with only data and type. Use 3 lists to organize the data together.

    public static class ShelterNode {
        private String data;
        private int type;
        private ShelterNode next;

        //type 1 means dog, 2 means cat
        public ShelterNode(String data, int type){
            this.data = data;
            this.type = type;
        }
    }

    public static class CatNode{
        private ShelterNode node;
        private CatNode next;

        public CatNode(ShelterNode node){
            this.node = node;
        }

    }

    public static class DogNode{
        private ShelterNode node;
        private DogNode next;

        public DogNode(ShelterNode node){
            this.node = node;
        }

    }


    public ShelterNode top;
    public ShelterNode bottom = top;
    public CatNode topCat;
    public CatNode bottomCat = topCat;
    public DogNode topDog;
    public DogNode bottomDog = topDog;


    public ChapterThree06S2(String name, int kind) {
        // TODO Auto-generated constructor stub
        top = new ShelterNode(name, kind);
        bottom = top;
    }

    public void enqueue(String name, int kind){
        ShelterNode SN = new ShelterNode(name, kind);
        //process top
        top.next = SN;
        top = SN;
        switch (kind) {
        case 1:
            topDog = new DogNode(SN);
            topDog = topDog.next;
            break;
        case 2:
            topCat = new CatNode(SN);
            topCat = topCat.next;
            break;
        default:
            break;
        }
    }
    public String dequeueany() throws EOFException{
        if(bottom == null) throw new EOFException();
        String animal = bottom.data;
        if(bottom.equals(bottomCat.node)){
            bottomCat = bottomCat.next;
        }
        else if(bottom.equals(bottomDog.node)){
            bottomDog = bottomDog.next;
        }
        bottom = bottom.next;
        return animal;
    }
    public String dequueueDog() throws EOFException{
        if(bottomDog == null) throw new EOFException();
        String animal = bottomDog.node.data;
        if(bottomDog.node.next != null){
            bottomDog.node = bottomDog.node.next;
        }
        if(bottomDog.next != null){
            bottomDog = bottomDog.next;
        }
        return animal;
    }
    public String dequueueCat() throws EOFException{
        if(bottomCat == null) throw new EOFException();
        String animal = bottomCat.node.data;
        if(bottomCat.node.next != null){
            bottomCat.node = bottomCat.node.next;
        }
        if(bottomCat.next != null){
            bottomCat = bottomCat.next;
        }
        return animal;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值