算法基础三之链表、栈、队列、递归

链表

单向链表

单向链表节点结构(可以实现成泛型)

public class Node<T> {
    public T value;
    public Node next;

    public Node(T value) {
        this.value = value;
    }
}

双向链表

public class DoubleNode {
    public int value;
    public DoubleNode pre;
    public DoubleNode next;

    public DoubleNode(int value) {
        this.value = value;
    }
}

单向链表和双向链表最简单的练习

链表相关的问题几乎都是coding问题

1)单链表和双链表怎么反转

package com.zh.class002;

public class ReverseList {
    public static void main(String[] args) {
        Node head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(3);
        Node node = reverseLinkedList(head);
        System.out.println(node.value);
        System.out.println(node.next.value);
        System.out.println(node.next.next.value);
    }
    public static Node reverseLinkedList(Node head) {
        Node pre = null;
        Node next = null;

        while (head != null) {
            next = head.next;
            head.next = pre;
            pre = head;
            head = next;
        }
        return pre;
    }

    public static DoubleNode reverseDoubleLinkedList(DoubleNode head) {
        DoubleNode pre = null;
        DoubleNode next = null;

        while (head != null) {
            next = head.next;

            head.next = pre;
            head.pre = next;

            pre = head;
            head = next;
        }
        return pre;
    }
}

 

2)把给定值都删除

package com.zh.class002;

public class DeleteGivenValue {
    public static void main(String[] args) {
        Node head = new Node(1);
        head.next = new Node(2);
        head.next.next = new Node(2);
        head.next.next.next = new Node(3);
        Node node = removeValue(head, 2);

        System.out.println(node);
    }
    public static Node removeValue(Node<Integer> head, int num) {
        // head来到第一个不需要删的位置
        while (head != null) {
            if (head.value == num) {
                head = head.next;
            } else {
                break;
            }
        }

        Node<Integer> pre = head;
        Node<Integer> cur = head;
        while (cur != null) {
            if (cur.value == num) {
                pre.next = cur.next;
            } else {
                pre = cur;
            }
            cur = cur.next;
        }
        return head;
    }
}

栈和队列

逻辑概念

栈:数据先进后出,犹如弹匣

队列:数据先进先出,好似队列

栈和队列的实际实现:

package com.zh.class002.stackandqueue;

import com.zh.class002.DoubleNode;

public class DoubleEndsQueue<T> {
    DoubleNode<T> head = null;
    DoubleNode<T> tail = null;
    public void addFromHead(T value) {
        DoubleNode<T> cur = new DoubleNode<>(value);
        if (head == null) {
            head = cur;
            tail = cur;
        } else {
            cur.next = head;
            head.pre = cur;
            head = cur;
        }
    }
    public void addFromBottom(T value) {
        DoubleNode<T> cur = new DoubleNode<>(value);
        if (head == null) {
            head = cur;
            tail = cur;
        } else {
            tail.next = cur;
            cur.pre = tail;
            tail = cur;
        }
    }

    public T popFromHead() {
        if (head == null) {
            return null;
        }
        DoubleNode<T> cur = head;
        if (head == tail) {
            head = null;
            tail = null;
        } else {
            head = head.next;
            cur.next = null;
            head.pre = null;
        }
        return cur.value;
    }

    public T popFromBottom() {
        if (head == null) {
            return null;
        }
        DoubleNode<T> cur = tail;
        if (head == tail) {
            head = null;
            tail = null;
        } else {
            tail = tail.pre;
            tail.next = null;
            cur.pre = null;
        }
        return cur.value;
    }

    public boolean isEmpty() {
        return head == null;
    }
}

双向链表实现

package com.zh.class002.stackandqueue;

public class MyStack<T> {
    private DoubleEndsQueue<T> queue;

    public MyStack() {
        queue = new DoubleEndsQueue();
    }

    public void push(T value) {
        queue.addFromHead(value);
    }

    public T pop() {
        return queue.popFromHead();
    }

    public boolean isEmpty() {
        return queue.isEmpty();
    }
}

 

package com.zh.class002.stackandqueue;

public class MyQueue<T> {
    private DoubleEndsQueue<T> queue;

    public MyQueue() {
        queue = new DoubleEndsQueue<T>();
    }

    public void push(T value) {
        queue.addFromHead(value);
    }

    public T poll() {
        return queue.popFromBottom();
    }

    public boolean isEmpty() {
        return queue.isEmpty();
    }
}

 

数组实现

package com.zh.class002.stackandqueue;

public class MyArrayStack {
    public static void main(String[] args) {
        MyArrayStack myArrayStack = new MyArrayStack(3);
        myArrayStack.push(1);
        myArrayStack.push(2);
        myArrayStack.push(3);
        System.out.println(myArrayStack.pop());
        myArrayStack.push(4);
        System.out.println(myArrayStack.pop());

    }
    private int[] arr;
    int index = 0;
    private final int limit;

    public MyArrayStack(int limit) {
        arr = new int[limit];
        this.limit = limit;
    }

    public void push(int value) {
        if (index == limit) {
            throw new RuntimeException("栈满了,不能再加了");
        }
        arr[index ++] = value;
    }

    public int pop() {
        if (index == 0) {
            throw new RuntimeException("栈空了,不能再拿了");
        }
        return arr[--index];
    }

    public boolean isEmpty() {
        return index == 0;
    }
}

 

package com.zh.class002.stackandqueue;

public class MyArrayQueue {
    private int[] arr;
    private int pushi;
    private int polli;
    private int size;
    private final int limit;

    public MyArrayQueue(int limit) {
        arr = new int[limit];
        pushi = 0;
        polli = 0;
        size = 0;
        this.limit = limit;
    }

    public void push(int value) {
        if (size == limit) {
            throw new RuntimeException("栈满了,不能再加了");
        }
        size++;
        arr[pushi] = value;
        pushi = nextIndex(pushi);
    }

    public int pop() {
        if (size == 0) {
            throw new RuntimeException("栈空了,不能再拿了");
        }
        size--;
        int ans = arr[polli];
        polli = nextIndex(polli);
        return ans;
    }

    public boolean isEmpty() {
        return size == 0;
    }

    // 如果现在的下标是i,返回下一个位置
    private int nextIndex(int i) {
        return i < limit - 1 ? i + 1 : 0;
    }
}

栈和队列的常见面试题

实现一个特殊的栈,在基本功能的基础上,再实现返回栈中最小元素的功能。

1)pop、push、getMin操作的时间复杂度都是O(1)。

2)设计的栈类型可以使用现成的栈结构。

实现一:双栈实现,一个栈存数据,另一个栈存最小值

package com.zh.class002;

import java.util.Stack;

public class GetMinStack {
    public static void main(String[] args) {
        GetMinStack getMinStack = new GetMinStack();
        getMinStack.push(1);
        getMinStack.push(2);
        getMinStack.push(3);
        System.out.println(getMinStack.getmin());
        getMinStack.pop();
        System.out.println(getMinStack.getmin());
        getMinStack.pop();
        System.out.println(getMinStack.getmin());
    }
    Stack<Integer> dataStack;
    Stack<Integer> minStack;

    public GetMinStack() {
        this.dataStack = new Stack<>();
        this.minStack = new Stack<>();
    }

    public void push(int newNum) {
        if (minStack.isEmpty()) {
            minStack.push(newNum);
        } else if (newNum < minStack.peek()) {
            minStack.push(newNum);
        } else {
            int newMin = minStack.peek();
            minStack.push(newMin);
        }
        dataStack.push(newNum);
    }

    public int pop() {
        if (this.dataStack.isEmpty()) {
            throw new RuntimeException("Your stack is empty.");
        }
        this.minStack.pop();
        return this.dataStack.pop();
    }

    public int getmin() {
        if (this.minStack.isEmpty()) {
            throw new RuntimeException("Your stack is empty.");
        }
        return this.minStack.peek();
    }
}

面试题二:

1)如何用栈结构实现队列结构

2)如何用队列结构是实现栈结构

栈实现队列

package com.zh.class002;

import java.util.Stack;

public class TwoStacksImplementQueue {
    public static void main(String[] args) {
        TwoStacksImplementQueue twoStacksImplementQueue = new TwoStacksImplementQueue();
        twoStacksImplementQueue.add(1);
        twoStacksImplementQueue.add(2);
        twoStacksImplementQueue.add(3);
        System.out.println(twoStacksImplementQueue.poll());
        System.out.println(twoStacksImplementQueue.poll());
        twoStacksImplementQueue.add(5);
        System.out.println(twoStacksImplementQueue.poll());
        System.out.println(twoStacksImplementQueue.poll());

    }
    Stack<Integer> stackPush;
    Stack<Integer> stackPop;

    public TwoStacksImplementQueue() {
        this.stackPush = new Stack<>();
        this.stackPop = new Stack<>();
    }

    public void add(int pushInt) {
        stackPush.push(pushInt);
        pushToPop();
    }

    private void pushToPop() {
        if (stackPop.isEmpty()) {
            while (!stackPush.isEmpty()) {
                stackPop.push(stackPush.pop());
            }
        }
    }

    public int poll() {
        if (stackPop.isEmpty() && stackPush.isEmpty()) {
            throw new RuntimeException("Queue is empty!");
        }
        pushToPop();
        return stackPop.pop();
    }

    public int peek() {
        if (stackPop.isEmpty() && stackPush.isEmpty()) {
            throw new RuntimeException("Queue is empty!");
        }
        pushToPop();
        return stackPop.peek();
    }
}

队列实现栈

package com.zh.class002;

import java.util.LinkedList;
import java.util.Queue;

public class TwoQueueImplementStack<T> {
    public Queue<T> queue;
    public Queue<T> help;

    public TwoQueueImplementStack() {
        queue = new LinkedList<>();
        help = new LinkedList<>();
    }

    public void push(T value) {
        queue.offer(value);
    }

    public T poll() {
        while (queue.size() > 1) {
            help.offer(queue.poll());
        }
        T ans = queue.poll();
        Queue<T> tmp = queue;
        queue = help;
        help = tmp;
        return ans;
    }

    public T peek() {
        while (queue.size() > 1) {
            help.offer(queue.poll());
        }
        T ans = queue.poll();
        help.offer(ans);
        Queue<T> tmp = queue;
        queue = help;
        help = tmp;
        return ans;
    }

    public boolean isEmpty() {
        return queue.isEmpty();
    }
}

递归:

例子:

求数组arr[L...R]中的最大值,怎么用递归方法实现

1)将[L...R]范围分成左右两半。左:[L...Mid],右[Mid+1...R]

2)左部分求最大值,右部分求最大值

3)[L...R]范围上的最大值,是max{左部分最大值,右部分最大值}

注意:2)是个递归过程,当范围上只有一个数,就可以不用再递归了

package com.zh.class002;

public class GetMax {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8,9,10};
        System.out.println(GetMax.getMax(arr));
    }
    public static int getMax(int[] arr) {
        return process(arr, 0, arr.length - 1);
    }

    public static int process(int[] arr, int l, int r) {
        if (l == r) {
            return arr[l];
        }
        int mid = l + (r - l) / 2;
        int leftMax = process(arr, l, mid);
        int rightMax = process(arr, mid + 1, r);
        return Math.max(leftMax, rightMax);
    }
}

对于符合下面公式的递归,时间复杂度是可以确认的

T(N)=aT(\frac{N}{b}) + O(N^{d})

其中a,b,d都是常数

对于上面的递归,假设L-R上有N个数

子问题的规模是N/2,调用了两次

因此a=2(调用次数)

b=2(子问题规模)

除此外,其他的复杂度都是常数次,因此d=0

结果如下:

 

上面复杂度确认a = 2, b = 2, d=0;因此复杂度为第一种,复杂度为O(N)

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值