题意:面试题06. 从尾到头打印链表
思路:首先遍历一遍链表获得链表的长度,使用此长度初始化数组。而后再从头至尾遍历一遍链表,并将遍历获得的数字从后往前插入数组。java
class Solution { public int[] reversePrint(ListNode head) { int len = 0; ListNode p = head; while (p != null) { p = p.next; len ++; } int[] res = new int[len]; p = head; while (p != null) { res[--len] = p.val; p = p.next; } return res; } }
题意:面试题09. 用两个栈实现队列
思路:“出队”操做,将一个栈的数据所有倒入到另外一个空栈中,以后另外一个栈的操做顺序即为队列的出栈顺序。node
class CQueue { Stack<Integer> in; Stack<Integer> out; public CQueue() { in = new Stack<>(); out = new Stack<>(); } public void appendTail(int value) { in.push(value); } public int deleteHead() { if (out.isEmpty()) { while (!in.isEmpty()) { out.push(in.pop()); } } return out.isEmpty() ? -1 : out.pop(); } }
题意:面试题18. 删除链表的节点
思路1:要删除单链表中的某一个节点node,首先须要找到node的前一个节点pre,而后把pre的next指针指向node的下一个节点便可。面试
class Solution { public ListNode deleteNode(ListNode head, int val) { if (head == null) { return head; } if (head.val == val) { return head.next; } ListNode p = head; while (p.next != null) { if (p.next.val == val) { p.next = p.next.next; break; } p = p.next; } return head; } }
思路2:上述思路1是在不能修改链表节点值的状况下的操做。若是能够修改链表的值,或者题目中没有给出链表头节点,只给出了要被删除的节点。
这时咱们能够使用后面的节点值覆盖前面节点的值来完成删除节点操做。参照面试题 02.03. 删除中间节点数组
class Solution { public void deleteNode(ListNode node) { ListNode p = node; ListNode q = node.next; while (q.next != null) { p.val = q.val; p = p.next; q = q.next; } p.val = q.val; p.next = null; } }
题意:面试题22. 链表中倒数第k个节点
思路:快慢双指针法。让快指针先走k步,而后快慢指针一块儿走,当快指针走到链表结尾的时候,慢指针就指向倒数第k个节点app
class Solution { public ListNode getKthFromEnd(ListNode head, int k) { ListNode p = head; while (p != null && k > 0) { p = p.next; k --; } if (p == null && k > 0) { return null; } ListNode q = head; while (p != null) { p = p.next; q = q.next; } return q; } }
题意:面试题24. 反转链表
思路:递归。先反转当前节点的后面节点,reverseList(head.next),这个函数返回的是反转以后的链表头,即最后一个节点。进行这步操做以后,当前节点下一个节点指向的是反转以后链表的尾部节点,即head.next,这时将head.next的下一个节点指向当前节点便可完成反转。dom
class Solution { public ListNode reverseList(ListNode head) { if (head == null) { return null; } if (head.next == null) { return head; } ListNode next = reverseList(head.next); head.next.next = head; head.next = null; return next; } }
题意:面试题25. 合并两个排序的链表
思路:双指针法。使用两个指针分别指向l1和l2的头结点,若是l1.val < l2.val,那么将l1指向的结点加入新的链表中,不然将l2指向的结点加入新的链表。函数
class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { ListNode head = new ListNode(-1); ListNode r = head; while (l1 != null && l2 != null) { if (l1.val > l2.val) { r.next = l2; l2 = l2.next; } else { r.next = l1; l1 = l1.next; } r = r.next; } r.next = (l1 == null) ? l2 : l1; return head.next; } }
题意:面试题30. 包含min函数的栈
思路:使用两个栈,一个栈data用来保存数据,另外一个栈min用来存data中最小值的信息。
1)入栈时,若当前入栈的元素x小于min栈中栈顶元素,那么将当前元素x同时压入data栈和min栈。
2)出栈时,若出栈元素x等于min的栈顶元素,那么将x也从min栈中弹出。ui
class MinStack { Stack<Integer> data; Stack<Integer> min; /** initialize your data structure here. */ public MinStack() { data = new Stack<>(); min = new Stack<>(); } public void push(int x) { data.push(x); if (min.isEmpty() || x <= min.peek()) { min.push(x); } } public void pop() { if (data.isEmpty()) { return; } int num = data.pop(); if (num == min.peek()) { min.pop(); } } public int top() { if (data.isEmpty()) { return -1; } return data.peek(); } public int min() { if (min.isEmpty()) { return -1; } return min.peek(); } } /** * Your MinStack object will be instantiated and called as such: * MinStack obj = new MinStack(); * obj.push(x); * obj.pop(); * int param_3 = obj.top(); * int param_4 = obj.min(); */
题意:面试题31. 栈的压入、弹出序列
思路:建一个栈来模拟题目中的压入、弹出操做。因为弹出序列中的第一个数字,必定是出如今栈顶时弹出的,如指针
pushed = [1,2,3,4,5], popped = [4,5,3,2,1]
中,弹出序列中的第一个元素4出栈时,压栈序列中必定是将4以及以前的元素压入栈内了。这时模拟弹出栈顶的元素4,而后接着比较弹出序列的下一个元素是否还与栈顶相同。
即每次将弹出序列的元素,与栈顶元素比较,相同则弹出,不一样则继续入栈元素,最后判断栈是否为空便可判断是否为合法的弹出序列。code
class Solution { public boolean validateStackSequences(int[] pushed, int[] popped) { Stack<Integer> stack = new Stack<>(); int pushIndex = 0; int popIndex = 0; while (pushIndex < pushed.length) { stack.push(pushed[pushIndex]); while (popIndex < popped.length && !stack.isEmpty() && popped[popIndex] == stack.peek()) { stack.pop(); popIndex ++; } pushIndex ++; } return stack.isEmpty(); } }
题意:面试题35. 复杂链表的复制
思路:链表除了next指针,还包含random指针。使用一个Map记录下已经建立的新结点,并将旧结点与新结点创建映射关系。在遍历过程当中对于已经建立过的结点直接从Map中取便可。
class Solution { Map<Node, Node> map = new HashMap<>(); public Node copyRandomList(Node head) { if (head == null) { return null; } if (map.get(head) != null) { return map.get(head); } Node newNode = new Node(head.val); map.put(head, newNode); newNode.next = copyRandomList(head.next); newNode.random = copyRandomList(head.random); return newNode; } }
题意:面试题41. 数据流中的中位数
思路:构造两个堆,一个大根堆,一个小根堆。使大根堆中记录数据流中较小部分的元素,小根堆中记录数据流中较大部分的元素。
使得小根堆中元素的值都大于大根堆中元素的值。即便小根堆的根结点值比大根堆的根结点值要大。
而且保证,在数据流的个数为偶数时,两个堆中的数据个数同样(此时中位数为两个堆堆顶元素的平均值)。数据流个数为奇数时,大根堆个数比小根堆多一个(此时中位数为大根堆的堆顶元素)。
class MedianFinder { PriorityQueue<Integer> min; PriorityQueue<Integer> max; /** initialize your data structure here. */ public MedianFinder() { min = new PriorityQueue(); max = new PriorityQueue(Collections.reverseOrder()); } public void addNum(int num) { if (max.size() == min.size()) { min.add(num); max.add(min.poll()); } else { max.add(num); min.add(max.poll()); } } public double findMedian() { return max.size() == min.size() ? (max.peek() + min.peek()) / 2.0 : max.peek(); } }
题意:面试题52. 两个链表的第一个公共节点
思路:先计算两个链表的长度。算出两个链表长度之差diff。较长的链表先走diff步以后,两个链表同时向后遍历,直到找到公共结点,或者到达两个链表结尾。
public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { if (headA == null || headB == null) { return null; } int lenA = len(headA); int lenB = len(headB); ListNode p = lenA > lenB ? headA : headB; ListNode q = p == headA ? headB : headA; int diff = Math.abs(lenA - lenB); while (diff > 0) { p = p.next; diff--; } while (p != null && q != null) { if (p == q) { return p; } p = p.next; q = q.next; } return null; } private int len(ListNode head) { ListNode tmp = head; int len = 0; while (tmp != null) { tmp = tmp.next; len ++; } return len; } }
题意:面试题59 - II. 队列的最大值
思路:单调栈。除了使用一个数据队列记录入队的元素,还要使用一个双端队列(单调的),维护一个从头至尾递减的序列。双端队列的队头元素即为队列的最大值。入数据队列时,若是元素大于双端队列的队尾元素,就要把队尾元素依次出队,而后把当前元素插入队列中。
当数据队列出队的元素等于双端队列的头元素时,双端队列的队头元素也要出队。
class MaxQueue { Queue<Integer> queue; Deque<Integer> maxValue; public MaxQueue() { queue = new LinkedList<>(); maxValue = new LinkedList<>(); } public int max_value() { if (maxValue.isEmpty()) { return -1; } return maxValue.peek(); } public void push_back(int value) { queue.add(value); while (!maxValue.isEmpty() && maxValue.getLast() < value) { maxValue.removeLast(); } maxValue.add(value); } public int pop_front() { if (maxValue.isEmpty()) { return -1; } int val = queue.poll(); if (val == maxValue.peek()) { maxValue.removeFirst(); } return val; } }